File: Mathlib/GroupTheory/CoprodI.lean

full_name: Monoid.CoprodI.Rel
code: /-- A relation on the free monoid on alphabet `Σ i, M i`,
relating `⟨i, 1⟩` with `1` and `⟨i, x⟩ * ⟨i, y⟩` with `⟨i, x * y⟩`. -/
inductive Monoid.CoprodI.Rel : FreeMonoid (Σi, M i) → FreeMonoid (Σi, M i) → Prop
  | of_one (i : ι) : Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, 1⟩) 1
  | of_mul {i : ι} (x y : M i) :
    Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, x⟩ * FreeMonoid.of ⟨i, y⟩) (FreeMonoid.of ⟨i, x * y⟩)
goal: FreeMonoid ((i : ι) × M i) → FreeMonoid ((i : ι) × M i) → Prop

full_name: Monoid.CoprodI.Rel.of_mul
code: /-- A relation on the free monoid on alphabet `Σ i, M i`,
relating `⟨i, 1⟩` with `1` and `⟨i, x⟩ * ⟨i, y⟩` with `⟨i, x * y⟩`. -/
inductive Monoid.CoprodI.Rel : FreeMonoid (Σi, M i) → FreeMonoid (Σi, M i) → Prop
  | of_one (i : ι) : Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, 1⟩) 1
  | of_mul {i : ι} (x y : M i) :
    Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, x⟩ * FreeMonoid.of ⟨i, y⟩) (FreeMonoid.of ⟨i, x * y⟩)
goal: Monoid.CoprodI.Rel M (FreeMonoid.of ⟨i, x⟩ * FreeMonoid.of ⟨i, y⟩) (FreeMonoid.of ⟨i, x * y⟩)

full_name: Monoid.CoprodI.Rel.of_one
code: /-- A relation on the free monoid on alphabet `Σ i, M i`,
relating `⟨i, 1⟩` with `1` and `⟨i, x⟩ * ⟨i, y⟩` with `⟨i, x * y⟩`. -/
inductive Monoid.CoprodI.Rel : FreeMonoid (Σi, M i) → FreeMonoid (Σi, M i) → Prop
  | of_one (i : ι) : Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, 1⟩) 1
  | of_mul {i : ι} (x y : M i) :
    Monoid.CoprodI.Rel (FreeMonoid.of ⟨i, x⟩ * FreeMonoid.of ⟨i, y⟩) (FreeMonoid.of ⟨i, x * y⟩)
goal: Monoid.CoprodI.Rel M (FreeMonoid.of ⟨i, 1⟩) 1

full_name: Monoid.CoprodI
code: /-- The free product (categorical coproduct) of an indexed family of monoids. -/
def Monoid.CoprodI : Type _ 
goal: Type (max u_1 u_2)

full_name: instMonoidCoprodI
code: instance : Monoid (Monoid.CoprodI M) 
goal: Monoid (Monoid.CoprodI M)

full_name: instInhabitedCoprodI
code: instance : Inhabited (Monoid.CoprodI M) 
goal: Inhabited (Monoid.CoprodI M)

full_name: Monoid.CoprodI.Word.toList
code: /-- The type of reduced words. A reduced word cannot contain a letter `1`, and no two adjacent
letters can come from the same summand. -/
@[ext]
structure Word where
  /-- A `Word` is a `List (Σ i, M i)`, such that `1` is not in the list, and no
  two adjacent letters are from the same summand -/
  toList : List (Σi, M i)
  /-- A reduced word does not contain `1` -/
  ne_one : ∀ l ∈ toList, Sigma.snd l ≠ 1
  /-- Adjacent letters are not from the same summand. -/
  chain_ne : toList.Chain' fun l l' => Sigma.fst l ≠ Sigma.fst l'
goal: List ((i : ι) × M i)

full_name: Monoid.CoprodI.Word.chain_ne
code: /-- The type of reduced words. A reduced word cannot contain a letter `1`, and no two adjacent
letters can come from the same summand. -/
@[ext]
structure Word where
  /-- A `Word` is a `List (Σ i, M i)`, such that `1` is not in the list, and no
  two adjacent letters are from the same summand -/
  toList : List (Σi, M i)
  /-- A reduced word does not contain `1` -/
  ne_one : ∀ l ∈ toList, Sigma.snd l ≠ 1
  /-- Adjacent letters are not from the same summand. -/
  chain_ne : toList.Chain' fun l l' => Sigma.fst l ≠ Sigma.fst l'
goal: List.Chain' (fun l l' => l.fst ≠ l'.fst) self.toList

full_name: Monoid.CoprodI.Word.ne_one
code: /-- The type of reduced words. A reduced word cannot contain a letter `1`, and no two adjacent
letters can come from the same summand. -/
@[ext]
structure Word where
  /-- A `Word` is a `List (Σ i, M i)`, such that `1` is not in the list, and no
  two adjacent letters are from the same summand -/
  toList : List (Σi, M i)
  /-- A reduced word does not contain `1` -/
  ne_one : ∀ l ∈ toList, Sigma.snd l ≠ 1
  /-- Adjacent letters are not from the same summand. -/
  chain_ne : toList.Chain' fun l l' => Sigma.fst l ≠ Sigma.fst l'
goal: l ∈ self.toList → l.snd ≠ 1

full_name: Monoid.CoprodI.Word
code: /-- The type of reduced words. A reduced word cannot contain a letter `1`, and no two adjacent
letters can come from the same summand. -/
@[ext]
structure Word where
  /-- A `Word` is a `List (Σ i, M i)`, such that `1` is not in the list, and no
  two adjacent letters are from the same summand -/
  toList : List (Σi, M i)
  /-- A reduced word does not contain `1` -/
  ne_one : ∀ l ∈ toList, Sigma.snd l ≠ 1
  /-- Adjacent letters are not from the same summand. -/
  chain_ne : toList.Chain' fun l l' => Sigma.fst l ≠ Sigma.fst l'
goal: Type (max u_1 u_2)

full_name: Monoid.CoprodI.of
code: /-- The inclusion of a summand into the free product. -/
def of {i : ι} : M i →* CoprodI M 
goal: M i →* Monoid.CoprodI M

full_name: Monoid.CoprodI.of_apply
code: theorem of_apply {i} (m : M i) : of m = Con.mk' _ (FreeMonoid.of <| Sigma.mk i m) 
goal: Monoid.CoprodI.of m = (conGen (Monoid.CoprodI.Rel M)).mk' (FreeMonoid.of ⟨i, m⟩)

full_name: Monoid.CoprodI.ext_hom
code: /-- See note [partially-applied ext lemmas]. -/
-- Porting note: higher `ext` priority
@[ext 1100]
theorem ext_hom (f g : CoprodI M →* N) (h : ∀ i, f.comp (of : M i →* _) = g.comp of) : f = g 
goal: f = g

full_name: Monoid.CoprodI.lift
code: /-- A map out of the free product corresponds to a family of maps out of the summands. This is the
universal property of the free product, characterizing it as a categorical coproduct. -/
@[simps symm_apply]
def lift : (∀ i, M i →* N) ≃ (CoprodI M →* N) 
goal: ((i : ι) → M i →* N) ≃ (Monoid.CoprodI M →* N)

full_name: Monoid.CoprodI.lift_symm_apply
code: /-- A map out of the free product corresponds to a family of maps out of the summands. This is the
universal property of the free product, characterizing it as a categorical coproduct. -/
@[simps symm_apply]
def lift : (∀ i, M i →* N) ≃ (CoprodI M →* N) 
goal: Monoid.CoprodI.lift.symm f i = f.comp Monoid.CoprodI.of

full_name: Monoid.CoprodI.lift_comp_of
code: @[simp]
theorem lift_comp_of {N} [Monoid N] (fi : ∀ i, M i →* N) i : (lift fi).comp of = fi i 
goal: (Monoid.CoprodI.lift fi).comp Monoid.CoprodI.of = fi i

full_name: Monoid.CoprodI.lift_of
code: @[simp]
theorem lift_of {N} [Monoid N] (fi : ∀ i, M i →* N) {i} (m : M i) : lift fi (of m) = fi i m 
goal: (Monoid.CoprodI.lift fi) (Monoid.CoprodI.of m) = (fi i) m

full_name: Monoid.CoprodI.lift_comp_of'
code: @[simp]
theorem lift_comp_of' {N} [Monoid N] (f : CoprodI M →* N) :
    lift (fun i ↦ f.comp (of (i := i))) = f 
goal: (Monoid.CoprodI.lift fun i => f.comp Monoid.CoprodI.of) = f

full_name: Monoid.CoprodI.lift_of'
code: @[simp]
theorem lift_of' : lift (fun i ↦ (of : M i →* CoprodI M)) = .id (CoprodI M) 
goal: (Monoid.CoprodI.lift fun i => Monoid.CoprodI.of) = MonoidHom.id (Monoid.CoprodI M)

full_name: Monoid.CoprodI.of_leftInverse
code: theorem of_leftInverse [DecidableEq ι] (i : ι) :
    Function.LeftInverse (lift <| Pi.mulSingle i (MonoidHom.id (M i))) of 
goal: Function.LeftInverse ⇑(Monoid.CoprodI.lift (Pi.mulSingle i (MonoidHom.id (M i)))) ⇑Monoid.CoprodI.of

full_name: Monoid.CoprodI.of_injective
code: theorem of_injective (i : ι) : Function.Injective (of : M i →* _) 
goal: Function.Injective ⇑Monoid.CoprodI.of

full_name: Monoid.CoprodI.mrange_eq_iSup
code: theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) 
goal: MonoidHom.mrange (Monoid.CoprodI.lift f) = ⨆ i, MonoidHom.mrange (f i)

full_name: Monoid.CoprodI.lift_mrange_le
code: theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N} :
    MonoidHom.mrange (lift f) ≤ s ↔ ∀ i, MonoidHom.mrange (f i) ≤ s 
goal: MonoidHom.mrange (Monoid.CoprodI.lift f) ≤ s ↔ ∀ (i : ι), MonoidHom.mrange (f i) ≤ s

full_name: Monoid.CoprodI.iSup_mrange_of
code: @[simp]
theorem iSup_mrange_of : ⨆ i, MonoidHom.mrange (of : M i →* CoprodI M) = ⊤ 
goal: ⨆ i, MonoidHom.mrange Monoid.CoprodI.of = ⊤

full_name: Monoid.CoprodI.mclosure_iUnion_range_of
code: @[simp]
theorem mclosure_iUnion_range_of :
    Submonoid.closure (⋃ i, Set.range (of : M i →* CoprodI M)) = ⊤ 
goal: Submonoid.closure (⋃ i, Set.range ⇑Monoid.CoprodI.of) = ⊤

full_name: Monoid.CoprodI.induction_left
code: @[elab_as_elim]
theorem induction_left {C : CoprodI M → Prop} (m : CoprodI M) (one : C 1)
    (mul : ∀ {i} (m : M i) x, C x → C (of m * x)) : C m 
goal: C m

full_name: Monoid.CoprodI.induction_on
code: @[elab_as_elim]
theorem induction_on {C : CoprodI M → Prop} (m : CoprodI M) (h_one : C 1)
    (h_of : ∀ (i) (m : M i), C (of m)) (h_mul : ∀ x y, C x → C y → C (x * y)) : C m 
goal: C m

full_name: Monoid.CoprodI.instInv
code: instance : Inv (CoprodI G) 
goal: Inv (Monoid.CoprodI G)

full_name: Monoid.CoprodI.inv_def
code: theorem inv_def (x : CoprodI G) :
    x⁻¹ =
      MulOpposite.unop
        (lift (fun i => (of : G i →* _).op.comp (MulEquiv.inv' (G i)).toMonoidHom) x) 
goal: x⁻¹ =
  MulOpposite.unop
    ((Monoid.CoprodI.lift fun i => (MonoidHom.op Monoid.CoprodI.of).comp (MulEquiv.inv' (G i)).toMonoidHom) x)

full_name: Monoid.CoprodI.instGroup
code: instance : Group (CoprodI G) 
goal: Group (Monoid.CoprodI G)

full_name: Monoid.CoprodI.lift_range_le
code: theorem lift_range_le {N} [Group N] (f : ∀ i, G i →* N) {s : Subgroup N}
    (h : ∀ i, (f i).range ≤ s) : (lift f).range ≤ s 
goal: (Monoid.CoprodI.lift f).range ≤ s

full_name: Monoid.CoprodI.range_eq_iSup
code: theorem range_eq_iSup {N} [Group N] (f : ∀ i, G i →* N) : (lift f).range = ⨆ i, (f i).range 
goal: (Monoid.CoprodI.lift f).range = ⨆ i, (f i).range

full_name: Monoid.CoprodI.Word.empty_toList
code: /-- The empty reduced word. -/
@[simps]
def empty : Word M 
goal: Monoid.CoprodI.Word.empty.toList = []

full_name: Monoid.CoprodI.Word.empty
code: /-- The empty reduced word. -/
@[simps]
def empty : Word M 
goal: Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.Word.instInhabited
code: instance : Inhabited (Word M) 
goal: Inhabited (Monoid.CoprodI.Word M)

full_name: Monoid.CoprodI.Word.prod
code: /-- A reduced word determines an element of the free product, given by multiplication. -/
def prod (w : Word M) : CoprodI M 
goal: Monoid.CoprodI M

full_name: Monoid.CoprodI.Word.prod_empty
code: @[simp]
theorem prod_empty : prod (empty : Word M) = 1 
goal: Monoid.CoprodI.Word.empty.prod = 1

full_name: Monoid.CoprodI.Word.fstIdx
code: /-- `fstIdx w` is `some i` if the first letter of `w` is `⟨i, m⟩` with `m : M i`. If `w` is empty
then it's `none`. -/
def fstIdx (w : Word M) : Option ι 
goal: Option ι

full_name: Monoid.CoprodI.Word.fstIdx_ne_iff
code: theorem fstIdx_ne_iff {w : Word M} {i} :
    fstIdx w ≠ some i ↔ ∀ l ∈ w.toList.head?, i ≠ Sigma.fst l 
goal: w.fstIdx ≠ some i ↔ ∀ l ∈ w.toList.head?, i ≠ l.fst

full_name: Monoid.CoprodI.Word.Pair.head
code: /-- Given an index `i : ι`, `Pair M i` is the type of pairs `(head, tail)` where `head : M i` and
`tail : Word M`, subject to the constraint that first letter of `tail` can't be `⟨i, m⟩`.
By prepending `head` to `tail`, one obtains a new word. We'll show that any word can be uniquely
obtained in this way. -/
@[ext]
structure Pair (i : ι) where
  /-- An element of `M i`, the first letter of the word. -/
  head : M i
  /-- The remaining letters of the word, excluding the first letter -/
  tail : Word M
  /-- The index first letter of tail of a `Pair M i` is not equal to `i` -/
  fstIdx_ne : fstIdx tail ≠ some i
goal: M i

full_name: Monoid.CoprodI.Word.Pair.tail
code: /-- Given an index `i : ι`, `Pair M i` is the type of pairs `(head, tail)` where `head : M i` and
`tail : Word M`, subject to the constraint that first letter of `tail` can't be `⟨i, m⟩`.
By prepending `head` to `tail`, one obtains a new word. We'll show that any word can be uniquely
obtained in this way. -/
@[ext]
structure Pair (i : ι) where
  /-- An element of `M i`, the first letter of the word. -/
  head : M i
  /-- The remaining letters of the word, excluding the first letter -/
  tail : Word M
  /-- The index first letter of tail of a `Pair M i` is not equal to `i` -/
  fstIdx_ne : fstIdx tail ≠ some i
goal: Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.Word.Pair.fstIdx_ne
code: /-- Given an index `i : ι`, `Pair M i` is the type of pairs `(head, tail)` where `head : M i` and
`tail : Word M`, subject to the constraint that first letter of `tail` can't be `⟨i, m⟩`.
By prepending `head` to `tail`, one obtains a new word. We'll show that any word can be uniquely
obtained in this way. -/
@[ext]
structure Pair (i : ι) where
  /-- An element of `M i`, the first letter of the word. -/
  head : M i
  /-- The remaining letters of the word, excluding the first letter -/
  tail : Word M
  /-- The index first letter of tail of a `Pair M i` is not equal to `i` -/
  fstIdx_ne : fstIdx tail ≠ some i
goal: self.tail.fstIdx ≠ some i

full_name: Monoid.CoprodI.Word.Pair
code: /-- Given an index `i : ι`, `Pair M i` is the type of pairs `(head, tail)` where `head : M i` and
`tail : Word M`, subject to the constraint that first letter of `tail` can't be `⟨i, m⟩`.
By prepending `head` to `tail`, one obtains a new word. We'll show that any word can be uniquely
obtained in this way. -/
@[ext]
structure Pair (i : ι) where
  /-- An element of `M i`, the first letter of the word. -/
  head : M i
  /-- The remaining letters of the word, excluding the first letter -/
  tail : Word M
  /-- The index first letter of tail of a `Pair M i` is not equal to `i` -/
  fstIdx_ne : fstIdx tail ≠ some i
goal: Type (max u_1 u_2)

full_name: Monoid.CoprodI.Word.instInhabitedPair
code: instance (i : ι) : Inhabited (Pair M i) 
goal: Inhabited (Monoid.CoprodI.Word.Pair M i)

full_name: Monoid.CoprodI.Word.cons_toList
code: /-- Construct a new `Word` without any reduction. The underlying list of
`cons m w _ _` is `⟨_, m⟩::w`  -/
@[simps]
def cons {i} (m : M i) (w : Word M) (hmw : w.fstIdx ≠ some i) (h1 : m ≠ 1) : Word M 
goal: (Monoid.CoprodI.Word.cons m w hmw h1).toList = ⟨i, m⟩ :: w.toList

full_name: Monoid.CoprodI.Word.cons
code: /-- Construct a new `Word` without any reduction. The underlying list of
`cons m w _ _` is `⟨_, m⟩::w`  -/
@[simps]
def cons {i} (m : M i) (w : Word M) (hmw : w.fstIdx ≠ some i) (h1 : m ≠ 1) : Word M 
goal: Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.Word.rcons
code: /-- Given a pair `(head, tail)`, we can form a word by prepending `head` to `tail`, except if `head`
is `1 : M i` then we have to just return `Word` since we need the result to be reduced. -/
def rcons {i} (p : Pair M i) : Word M 
goal: Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.Word.prod_rcons
code: @[simp]
theorem prod_rcons {i} (p : Pair M i) : prod (rcons p) = of p.head * prod p.tail 
goal: (Monoid.CoprodI.Word.rcons p).prod = Monoid.CoprodI.of p.head * p.tail.prod

full_name: Monoid.CoprodI.Word.rcons_inj
code: theorem rcons_inj {i} : Function.Injective (rcons : Pair M i → Word M) 
goal: Function.Injective Monoid.CoprodI.Word.rcons

full_name: Monoid.CoprodI.Word.mem_rcons_iff
code: theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) 
goal: ⟨j, m⟩ ∈ (Monoid.CoprodI.Word.rcons p).toList ↔ ⟨j, m⟩ ∈ p.tail.toList ∨ m ≠ 1 ∧ ∃ (h : i = j), m = h ▸ p.head

full_name: Monoid.CoprodI.Word.fstIdx_cons
code: @[simp]
theorem fstIdx_cons {i} (m : M i) (w : Word M) (hmw : w.fstIdx ≠ some i) (h1 : m ≠ 1) :
    fstIdx (cons m w hmw h1) = some i 
goal: (Monoid.CoprodI.Word.cons m w hmw h1).fstIdx = some i

full_name: Monoid.CoprodI.Word.prod_cons
code: @[simp]
theorem prod_cons (i) (m : M i) (w : Word M) (h1 : m ≠ 1) (h2 : w.fstIdx ≠ some i) :
    prod (cons m w h2 h1) = of m * prod w 
goal: (Monoid.CoprodI.Word.cons m w h2 h1).prod = Monoid.CoprodI.of m * w.prod

full_name: Monoid.CoprodI.Word.consRecOn
code: /-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w 
goal: motive w

full_name: Monoid.CoprodI.Word.consRecOn_empty
code: @[simp]
theorem consRecOn_empty {motive : Word M → Sort*} (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    consRecOn empty h_empty h_cons = h_empty 
goal: Monoid.CoprodI.Word.consRecOn Monoid.CoprodI.Word.empty h_empty h_cons = h_empty

full_name: Monoid.CoprodI.Word.consRecOn_cons
code: @[simp]
theorem consRecOn_cons {motive : Word M → Sort*} (i) (m : M i) (w : Word M) h1 h2
    (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    consRecOn (cons m w h1 h2) h_empty h_cons = h_cons i m w h1 h2
      (consRecOn w h_empty h_cons) 
goal: Monoid.CoprodI.Word.consRecOn (Monoid.CoprodI.Word.cons m w h1 h2) h_empty h_cons =
  h_cons i m w h1 h2 (Monoid.CoprodI.Word.consRecOn w h_empty h_cons)

full_name: _private.Mathlib.GroupTheory.CoprodI.0.Monoid.CoprodI.Word.equivPairAux
code: /-- Given `i : ι`, any reduced word can be decomposed into a pair `p` such that `w = rcons p`. -/
private def equivPairAux (i) (w : Word M) : { p : Pair M i // rcons p = w } 
goal: { p // Monoid.CoprodI.Word.rcons p = w }

full_name: Monoid.CoprodI.Word.equivPair
code: /-- The equivalence between words and pairs. Given a word, it decomposes it as a pair by removing
the first letter if it comes from `M i`. Given a pair, it prepends the head to the tail. -/
def equivPair (i) : Word M ≃ Pair M i 
goal: Monoid.CoprodI.Word M ≃ Monoid.CoprodI.Word.Pair M i

full_name: Monoid.CoprodI.Word.equivPair_symm
code: theorem equivPair_symm (i) (p : Pair M i) : (equivPair i).symm p = rcons p 
goal: (Monoid.CoprodI.Word.equivPair i).symm p = Monoid.CoprodI.Word.rcons p

full_name: Monoid.CoprodI.Word.equivPair_eq_of_fstIdx_ne
code: theorem equivPair_eq_of_fstIdx_ne {i} {w : Word M} (h : fstIdx w ≠ some i) :
    equivPair i w = ⟨1, w, h⟩ 
goal: (Monoid.CoprodI.Word.equivPair i) w = { head := 1, tail := w, fstIdx_ne := h }

full_name: Monoid.CoprodI.Word.mem_equivPair_tail_iff
code: theorem mem_equivPair_tail_iff {i j : ι} {w : Word M} (m : M i) :
    (⟨i, m⟩ ∈ (equivPair j w).tail.toList) ↔ ⟨i, m⟩ ∈ w.toList.tail
      ∨ i ≠ j ∧ ∃ h : w.toList ≠ [], w.toList.head h = ⟨i, m⟩ 
goal: ⟨i, m⟩ ∈ ((Monoid.CoprodI.Word.equivPair j) w).tail.toList ↔
  ⟨i, m⟩ ∈ w.toList.tail ∨ i ≠ j ∧ ∃ (h : w.toList ≠ []), w.toList.head h = ⟨i, m⟩

full_name: Monoid.CoprodI.Word.mem_of_mem_equivPair_tail
code: theorem mem_of_mem_equivPair_tail {i j : ι} {w : Word M} (m : M i) :
    (⟨i, m⟩ ∈ (equivPair j w).tail.toList) → ⟨i, m⟩ ∈ w.toList 
goal: ⟨i, m⟩ ∈ ((Monoid.CoprodI.Word.equivPair j) w).tail.toList → ⟨i, m⟩ ∈ w.toList

full_name: Monoid.CoprodI.Word.equivPair_head
code: theorem equivPair_head {i : ι} {w : Word M} :
    (equivPair i w).head =
      if h : ∃ (h : w.toList ≠ []), (w.toList.head h).1 = i
      then h.snd ▸ (w.toList.head h.1).2
      else 1 
goal: ((Monoid.CoprodI.Word.equivPair i) w).head =
  if h : ∃ (h : w.toList ≠ []), (w.toList.head h).fst = i then ⋯ ▸ (w.toList.head ⋯).snd else 1

full_name: Monoid.CoprodI.Word.summandAction
code: instance summandAction (i) : MulAction (M i) (Word M) 
goal: MulAction (M i) (Monoid.CoprodI.Word M)

full_name: Monoid.CoprodI.Word.instMulAction
code: instance : MulAction (CoprodI M) (Word M) 
goal: MulAction (Monoid.CoprodI M) (Monoid.CoprodI.Word M)

full_name: Monoid.CoprodI.Word.smul_def
code: theorem smul_def {i} (m : M i) (w : Word M) :
    m • w = rcons { equivPair i w with head := m * (equivPair i w).head } 
goal: m • w =
  Monoid.CoprodI.Word.rcons
    (let __src := (Monoid.CoprodI.Word.equivPair i) w;
    { head := m * ((Monoid.CoprodI.Word.equivPair i) w).head, tail := __src.tail, fstIdx_ne := ⋯ })

full_name: Monoid.CoprodI.Word.of_smul_def
code: theorem of_smul_def (i) (w : Word M) (m : M i) :
    of m • w = rcons { equivPair i w with head := m * (equivPair i w).head } 
goal: Monoid.CoprodI.of m • w =
  Monoid.CoprodI.Word.rcons
    (let __src := (Monoid.CoprodI.Word.equivPair i) w;
    { head := m * ((Monoid.CoprodI.Word.equivPair i) w).head, tail := __src.tail, fstIdx_ne := ⋯ })

full_name: Monoid.CoprodI.Word.equivPair_smul_same
code: theorem equivPair_smul_same {i} (m : M i) (w : Word M) :
    equivPair i (of m • w) = ⟨m * (equivPair i w).head, (equivPair i w).tail,
      (equivPair i w).fstIdx_ne⟩ 
goal: (Monoid.CoprodI.Word.equivPair i) (Monoid.CoprodI.of m • w) =
  { head := m * ((Monoid.CoprodI.Word.equivPair i) w).head, tail := ((Monoid.CoprodI.Word.equivPair i) w).tail,
    fstIdx_ne := ⋯ }

full_name: Monoid.CoprodI.Word.equivPair_tail
code: @[simp]
theorem equivPair_tail {i} (p : Pair M i) :
    equivPair i p.tail = ⟨1, p.tail, p.fstIdx_ne⟩ 
goal: (Monoid.CoprodI.Word.equivPair i) p.tail = { head := 1, tail := p.tail, fstIdx_ne := ⋯ }

full_name: Monoid.CoprodI.Word.smul_eq_of_smul
code: theorem smul_eq_of_smul {i} (m : M i) (w : Word M) :
    m • w = of m • w 
goal: m • w = Monoid.CoprodI.of m • w

full_name: Monoid.CoprodI.Word.mem_smul_iff
code: theorem mem_smul_iff {i j : ι} {m₁ : M i} {m₂ : M j} {w : Word M} :
    ⟨_, m₁⟩ ∈ (of m₂ • w).toList ↔
      (¬i = j ∧ ⟨i, m₁⟩ ∈ w.toList)
      ∨ (m₁ ≠ 1 ∧ ∃ (hij : i = j),(⟨i, m₁⟩ ∈ w.toList.tail) ∨
        (∃ m', ⟨j, m'⟩ ∈ w.toList.head? ∧ m₁ = hij ▸ (m₂ * m')) ∨
        (w.fstIdx ≠ some j ∧ m₁ = hij ▸ m₂)) 
goal: ⟨i, m₁⟩ ∈ (Monoid.CoprodI.of m₂ • w).toList ↔
  ¬i = j ∧ ⟨i, m₁⟩ ∈ w.toList ∨
    m₁ ≠ 1 ∧
      ∃ (hij : i = j),
        ⟨i, m₁⟩ ∈ w.toList.tail ∨
          (∃ m', ⟨j, m'⟩ ∈ w.toList.head? ∧ m₁ = ⋯ ▸ (m₂ * m')) ∨ w.fstIdx ≠ some j ∧ m₁ = ⋯ ▸ m₂

full_name: Monoid.CoprodI.Word.mem_smul_iff_of_ne
code: theorem mem_smul_iff_of_ne {i j : ι} (hij : i ≠ j) {m₁ : M i} {m₂ : M j} {w : Word M} :
    ⟨_, m₁⟩ ∈ (of m₂ • w).toList ↔ ⟨i, m₁⟩ ∈ w.toList 
goal: ⟨i, m₁⟩ ∈ (Monoid.CoprodI.of m₂ • w).toList ↔ ⟨i, m₁⟩ ∈ w.toList

full_name: Monoid.CoprodI.Word.cons_eq_smul
code: theorem cons_eq_smul {i} {m : M i} {ls h1 h2} :
    cons m ls h1 h2 = of m • ls 
goal: Monoid.CoprodI.Word.cons m ls h1 h2 = Monoid.CoprodI.of m • ls

full_name: Monoid.CoprodI.Word.rcons_eq_smul
code: theorem rcons_eq_smul {i} (p : Pair M i) :
    rcons p = of p.head • p.tail 
goal: Monoid.CoprodI.Word.rcons p = Monoid.CoprodI.of p.head • p.tail

full_name: Monoid.CoprodI.Word.equivPair_head_smul_equivPair_tail
code: @[simp]
theorem equivPair_head_smul_equivPair_tail {i : ι} (w : Word M) :
    of (equivPair i w).head • (equivPair i w).tail = w 
goal: Monoid.CoprodI.of ((Monoid.CoprodI.Word.equivPair i) w).head • ((Monoid.CoprodI.Word.equivPair i) w).tail = w

full_name: Monoid.CoprodI.Word.equivPair_tail_eq_inv_smul
code: theorem equivPair_tail_eq_inv_smul {G : ι → Type*} [∀ i, Group (G i)]
    [∀i, DecidableEq (G i)] {i} (w : Word G) :
    (equivPair i w).tail = (of (equivPair i w).head)⁻¹ • w 
goal: ((Monoid.CoprodI.Word.equivPair i) w).tail = (Monoid.CoprodI.of ((Monoid.CoprodI.Word.equivPair i) w).head)⁻¹ • w

full_name: Monoid.CoprodI.Word.smul_induction
code: theorem smul_induction {C : Word M → Prop} (h_empty : C empty)
    (h_smul : ∀ (i) (m : M i) (w), C w → C (of m • w)) (w : Word M) : C w 
goal: C w

full_name: Monoid.CoprodI.Word.prod_smul
code: @[simp]
theorem prod_smul (m) : ∀ w : Word M, prod (m • w) = m * prod w 
goal: (m • w).prod = m * w.prod

full_name: Monoid.CoprodI.Word.equiv
code: /-- Each element of the free product corresponds to a unique reduced word. -/
def equiv : CoprodI M ≃ Word M 
goal: Monoid.CoprodI M ≃ Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.Word.instDecidableEq
code: instance : DecidableEq (Word M) 
goal: DecidableEq (Monoid.CoprodI.Word M)

full_name: Monoid.CoprodI.Word.instDecidableEq_1
code: instance : DecidableEq (CoprodI M) 
goal: DecidableEq (Monoid.CoprodI M)

full_name: Monoid.CoprodI.NeWord.singleton
code: /-- A `NeWord M i j` is a representation of a non-empty reduced words where the first letter comes
from `M i` and the last letter comes from `M j`. It can be constructed from singletons and via
concatenation, and thus provides a useful induction principle. -/
--@[nolint has_nonempty_instance] Porting note(#5171): commented out
inductive NeWord : ι → ι → Type _
  | singleton : ∀ {i : ι} (x : M i), x ≠ 1 → NeWord i i
  | append : ∀ {i j k l} (_w₁ : NeWord i j) (_hne : j ≠ k) (_w₂ : NeWord k l), NeWord i l
goal: x ≠ 1 → Monoid.CoprodI.NeWord M i i

full_name: Monoid.CoprodI.NeWord.append
code: /-- A `NeWord M i j` is a representation of a non-empty reduced words where the first letter comes
from `M i` and the last letter comes from `M j`. It can be constructed from singletons and via
concatenation, and thus provides a useful induction principle. -/
--@[nolint has_nonempty_instance] Porting note(#5171): commented out
inductive NeWord : ι → ι → Type _
  | singleton : ∀ {i : ι} (x : M i), x ≠ 1 → NeWord i i
  | append : ∀ {i j k l} (_w₁ : NeWord i j) (_hne : j ≠ k) (_w₂ : NeWord k l), NeWord i l
goal: Monoid.CoprodI.NeWord M i l

full_name: Monoid.CoprodI.NeWord
code: /-- A `NeWord M i j` is a representation of a non-empty reduced words where the first letter comes
from `M i` and the last letter comes from `M j`. It can be constructed from singletons and via
concatenation, and thus provides a useful induction principle. -/
--@[nolint has_nonempty_instance] Porting note(#5171): commented out
inductive NeWord : ι → ι → Type _
  | singleton : ∀ {i : ι} (x : M i), x ≠ 1 → NeWord i i
  | append : ∀ {i j k l} (_w₁ : NeWord i j) (_hne : j ≠ k) (_w₂ : NeWord k l), NeWord i l
goal: ι → ι → Type (max u_1 u_2)

full_name: Monoid.CoprodI.NeWord.toList
code: /-- The list represented by a given `NeWord` -/
@[simp]
def toList : ∀ {i j} (_w : NeWord M i j), List (Σi, M i)
  
goal: List ((i : ι) × M i)

full_name: Monoid.CoprodI.NeWord.toList_ne_nil
code: theorem toList_ne_nil {i j} (w : NeWord M i j) : w.toList ≠ List.nil 
goal: w.toList ≠ []

full_name: Monoid.CoprodI.NeWord.head
code: /-- The first letter of a `NeWord` -/
@[simp]
def head : ∀ {i j} (_w : NeWord M i j), M i
  
goal: M i

full_name: Monoid.CoprodI.NeWord.last
code: /-- The last letter of a `NeWord` -/
@[simp]
def last : ∀ {i j} (_w : NeWord M i j), M j
  
goal: M j

full_name: Monoid.CoprodI.NeWord.toList_head?
code: @[simp]
theorem toList_head? {i j} (w : NeWord M i j) : w.toList.head? = Option.some ⟨i, w.head⟩ 
goal: w.toList.head? = some ⟨i, w.head⟩

full_name: Monoid.CoprodI.NeWord.toList_getLast?
code: @[simp]
theorem toList_getLast? {i j} (w : NeWord M i j) : w.toList.getLast? = Option.some ⟨j, w.last⟩ 
goal: w.toList.getLast? = some ⟨j, w.last⟩

full_name: Monoid.CoprodI.NeWord.toWord
code: /-- The `Word M` represented by a `NeWord M i j` -/
def toWord {i j} (w : NeWord M i j) : Word M 
goal: Monoid.CoprodI.Word M

full_name: Monoid.CoprodI.NeWord.of_word
code: /-- Every nonempty `Word M` can be constructed as a `NeWord M i j` -/
theorem of_word (w : Word M) (h : w ≠ empty) : ∃ (i j : _) (w' : NeWord M i j), w'.toWord = w 
goal: ∃ i j w', w'.toWord = w

full_name: Monoid.CoprodI.NeWord.prod
code: /-- A non-empty reduced word determines an element of the free product, given by multiplication. -/
def prod {i j} (w : NeWord M i j) 
goal: Monoid.CoprodI M

full_name: Monoid.CoprodI.NeWord.singleton_head
code: @[simp]
theorem singleton_head {i} (x : M i) (hne_one : x ≠ 1) : (singleton x hne_one).head = x 
goal: (Monoid.CoprodI.NeWord.singleton x hne_one).head = x

full_name: Monoid.CoprodI.NeWord.singleton_last
code: @[simp]
theorem singleton_last {i} (x : M i) (hne_one : x ≠ 1) : (singleton x hne_one).last = x 
goal: (Monoid.CoprodI.NeWord.singleton x hne_one).last = x

full_name: Monoid.CoprodI.NeWord.prod_singleton
code: @[simp]
theorem prod_singleton {i} (x : M i) (hne_one : x ≠ 1) : (singleton x hne_one).prod = of x 
goal: (Monoid.CoprodI.NeWord.singleton x hne_one).prod = Monoid.CoprodI.of x

full_name: Monoid.CoprodI.NeWord.append_head
code: @[simp]
theorem append_head {i j k l} {w₁ : NeWord M i j} {hne : j ≠ k} {w₂ : NeWord M k l} :
    (append w₁ hne w₂).head = w₁.head 
goal: (w₁.append hne w₂).head = w₁.head

full_name: Monoid.CoprodI.NeWord.append_last
code: @[simp]
theorem append_last {i j k l} {w₁ : NeWord M i j} {hne : j ≠ k} {w₂ : NeWord M k l} :
    (append w₁ hne w₂).last = w₂.last 
goal: (w₁.append hne w₂).last = w₂.last

full_name: Monoid.CoprodI.NeWord.append_prod
code: @[simp]
theorem append_prod {i j k l} {w₁ : NeWord M i j} {hne : j ≠ k} {w₂ : NeWord M k l} :
    (append w₁ hne w₂).prod = w₁.prod * w₂.prod 
goal: (w₁.append hne w₂).prod = w₁.prod * w₂.prod

full_name: Monoid.CoprodI.NeWord.replaceHead
code: /-- One can replace the first letter in a non-empty reduced word by an element of the same
group -/
def replaceHead : ∀ {i j : ι} (x : M i) (_hnotone : x ≠ 1) (_w : NeWord M i j), NeWord M i j
  
goal: Monoid.CoprodI.NeWord M i j

full_name: Monoid.CoprodI.NeWord.replaceHead_head
code: @[simp]
theorem replaceHead_head {i j : ι} (x : M i) (hnotone : x ≠ 1) (w : NeWord M i j) :
    (replaceHead x hnotone w).head = x 
goal: (Monoid.CoprodI.NeWord.replaceHead x hnotone w).head = x

full_name: Monoid.CoprodI.NeWord.mulHead
code: /-- One can multiply an element from the left to a non-empty reduced word if it does not cancel
with the first element in the word. -/
def mulHead {i j : ι} (w : NeWord M i j) (x : M i) (hnotone : x * w.head ≠ 1) : NeWord M i j 
goal: Monoid.CoprodI.NeWord M i j

full_name: Monoid.CoprodI.NeWord.mulHead_head
code: @[simp]
theorem mulHead_head {i j : ι} (w : NeWord M i j) (x : M i) (hnotone : x * w.head ≠ 1) :
    (mulHead w x hnotone).head = x * w.head 
goal: (w.mulHead x hnotone).head = x * w.head

full_name: Monoid.CoprodI.NeWord.mulHead_prod
code: @[simp]
theorem mulHead_prod {i j : ι} (w : NeWord M i j) (x : M i) (hnotone : x * w.head ≠ 1) :
    (mulHead w x hnotone).prod = of x * w.prod 
goal: (w.mulHead x hnotone).prod = Monoid.CoprodI.of x * w.prod

full_name: Monoid.CoprodI.NeWord.inv
code: /-- The inverse of a non-empty reduced word -/
def inv : ∀ {i j} (_w : NeWord G i j), NeWord G j i
  
goal: Monoid.CoprodI.NeWord G j i

full_name: Monoid.CoprodI.NeWord.inv_prod
code: @[simp]
theorem inv_prod {i j} (w : NeWord G i j) : w.inv.prod = w.prod⁻¹ 
goal: w.inv.prod = w.prod⁻¹

full_name: Monoid.CoprodI.NeWord.inv_head
code: @[simp]
theorem inv_head {i j} (w : NeWord G i j) : w.inv.head = w.last⁻¹ 
goal: w.inv.head = w.last⁻¹

full_name: Monoid.CoprodI.NeWord.inv_last
code: @[simp]
theorem inv_last {i j} (w : NeWord G i j) : w.inv.last = w.head⁻¹ 
goal: w.inv.last = w.head⁻¹

full_name: Monoid.CoprodI.lift_word_ping_pong
code: theorem lift_word_ping_pong {i j k} (w : NeWord H i j) (hk : j ≠ k) :
    lift f w.prod • X k ⊆ X i 
goal: (Monoid.CoprodI.lift f) w.prod • X k ⊆ X i

full_name: Monoid.CoprodI.lift_word_prod_nontrivial_of_other_i
code: theorem lift_word_prod_nontrivial_of_other_i {i j k} (w : NeWord H i j) (hhead : k ≠ i)
    (hlast : k ≠ j) : lift f w.prod ≠ 1 
goal: (Monoid.CoprodI.lift f) w.prod ≠ 1

full_name: Monoid.CoprodI.lift_word_prod_nontrivial_of_head_eq_last
code: theorem lift_word_prod_nontrivial_of_head_eq_last {i} (w : NeWord H i i) : lift f w.prod ≠ 1 
goal: (Monoid.CoprodI.lift f) w.prod ≠ 1

full_name: Monoid.CoprodI.lift_word_prod_nontrivial_of_head_card
code: theorem lift_word_prod_nontrivial_of_head_card {i j} (w : NeWord H i j) (hcard : 3 ≤ #(H i))
    (hheadtail : i ≠ j) : lift f w.prod ≠ 1 
goal: (Monoid.CoprodI.lift f) w.prod ≠ 1

full_name: Monoid.CoprodI.lift_word_prod_nontrivial_of_not_empty
code: theorem lift_word_prod_nontrivial_of_not_empty {i j} (w : NeWord H i j) : lift f w.prod ≠ 1 
goal: (Monoid.CoprodI.lift f) w.prod ≠ 1

full_name: Monoid.CoprodI.empty_of_word_prod_eq_one
code: theorem empty_of_word_prod_eq_one {w : Word H} (h : lift f w.prod = 1) : w = Word.empty 
goal: w = Monoid.CoprodI.Word.empty

full_name: Monoid.CoprodI.lift_injective_of_ping_pong
code: /-- The **Ping-Pong-Lemma**.

Given a group action of `G` on `X` so that the `H i` acts in a specific way on disjoint subsets
`X i` we can prove that `lift f` is injective, and thus the image of `lift f` is isomorphic to the
free product of the `H i`.

Often the Ping-Pong-Lemma is stated with regard to subgroups `H i` that generate the whole group;
we generalize to arbitrary group homomorphisms `f i : H i →* G` and do not require the group to be
generated by the images.

Usually the Ping-Pong-Lemma requires that one group `H i` has at least three elements. This
condition is only needed if `# ι = 2`, and we accept `3 ≤ # ι` as an alternative.
-/
theorem lift_injective_of_ping_pong : Function.Injective (lift f) 
goal: Function.Injective ⇑(Monoid.CoprodI.lift f)

full_name: Monoid.CoprodI.FreeGroupBasis.coprodI
code: /-- Given a family of free groups with distinguished bases, then their free product is free, with
a basis given by the union of the bases of the components. -/
def FreeGroupBasis.coprodI {ι : Type*} {X : ι → Type*} {G : ι → Type*} [∀ i, Group (G i)]
    (B : ∀ i, FreeGroupBasis (X i) (G i)) :
    FreeGroupBasis (Σ i, X i) (CoprodI G) 
goal: FreeGroupBasis ((i : ι) × X i) (Monoid.CoprodI G)

full_name: Monoid.CoprodI.instIsFreeGroup
code: /-- The free product of free groups is itself a free group. -/
instance {ι : Type*} (G : ι → Type*) [∀ i, Group (G i)] [∀ i, IsFreeGroup (G i)] :
    IsFreeGroup (CoprodI G) 
goal: IsFreeGroup (Monoid.CoprodI G)

full_name: freeGroupEquivCoprodI_apply
code: /-- A free group is a free product of copies of the free_group over one generator. -/
@[simps!]
def _root_.freeGroupEquivCoprodI {ι : Type u_1} :
    FreeGroup ι ≃* CoprodI fun _ : ι => FreeGroup Unit 
goal: freeGroupEquivCoprodI a = (FreeGroup.lift fun i => Monoid.CoprodI.of (FreeGroup.of ())) a

full_name: freeGroupEquivCoprodI_symm_apply
code: /-- A free group is a free product of copies of the free_group over one generator. -/
@[simps!]
def _root_.freeGroupEquivCoprodI {ι : Type u_1} :
    FreeGroup ι ≃* CoprodI fun _ : ι => FreeGroup Unit 
goal: freeGroupEquivCoprodI.symm a = (Monoid.CoprodI.lift fun i => FreeGroup.lift fun x => FreeGroup.of i) a

full_name: freeGroupEquivCoprodI
code: /-- A free group is a free product of copies of the free_group over one generator. -/
@[simps!]
def _root_.freeGroupEquivCoprodI {ι : Type u_1} :
    FreeGroup ι ≃* CoprodI fun _ : ι => FreeGroup Unit 
goal: FreeGroup ι ≃* Monoid.CoprodI fun x => FreeGroup Unit

full_name: FreeGroup.injective_lift_of_ping_pong
code: /-- The Ping-Pong-Lemma.

Given a group action of `G` on `X` so that the generators of the free groups act in specific
ways on disjoint subsets `X i` and `Y i` we can prove that `lift f` is injective, and thus the image
of `lift f` is isomorphic to the free group.

Often the Ping-Pong-Lemma is stated with regard to group elements that generate the whole group;
we generalize to arbitrary group homomorphisms from the free group to `G` and do not require the
group to be generated by the elements.
-/
theorem _root_.FreeGroup.injective_lift_of_ping_pong : Function.Injective (FreeGroup.lift a) 
goal: Function.Injective ⇑(FreeGroup.lift a)