l3lab/ntp-mathlib huggingface dataset:
theorem lift_word_prod_nontrivial_of_not_empty {i j} (w : NeWord H i j) : lift f w.prod ≠ 1 := by
  classical
    cases' hcard with hcard hcard
    · obtain ⟨i, h1, h2⟩ := Cardinal.three_le hcard i j
      exact lift_word_prod_nontrivial_of_other_i f X hXnonempty hXdisj hpp w h1 h2
    · cases' hcard with k hcard
      by_cases hh : i = k <;> by_cases hl : j = k
      · subst hh
        subst hl
        exact lift_word_prod_nontrivial_of_head_eq_last f X hXnonempty hXdisj hpp w
      · subst hh
        change j ≠ i at hl
        exact lift_word_prod_nontrivial_of_head_card f X hXnonempty hXdisj hpp w hcard hl.symm
      · subst hl
        change i ≠ j at hh
        have : lift f w.inv.prod ≠ 1 :=
          lift_word_prod_nontrivial_of_head_card f X hXnonempty hXdisj hpp w.inv hcard hh.symm
        intro heq
        apply this
        simpa using heq
      · change i ≠ k at hh
        change j ≠ k at hl
        obtain ⟨h, hn1, -⟩ := Cardinal.three_le hcard 1 1
        let w' : NeWord H k k :=
          NeWord.append (NeWord.append (NeWord.singleton h hn1) hh.symm w) hl
            (NeWord.singleton h⁻¹ (inv_ne_one.mpr hn1))
        have hw' : lift f w'.prod ≠ 1 :=
          lift_word_prod_nontrivial_of_head_eq_last f X hXnonempty hXdisj hpp w'
        intro heq1
        apply hw'
        

Proof state:
case neg.intro.intro
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
i j : ι
w : NeWord H i j
k : ι
hcard : 3 ≤ #(H k)
hh : i ≠ k
hl : j ≠ k
h : H k
hn1 : h ≠ 1
w' : NeWord H k k :=
  NeWord.append (NeWord.append (NeWord.singleton h hn1) (_ : k ≠ i) w) hl (NeWord.singleton h⁻¹ (_ : h⁻¹ ≠ 1))
hw' : (lift f) (NeWord.prod w') ≠ 1
heq1 : (lift f) (NeWord.prod w) = 1
⊢ (lift f) (NeWord.prod w') = 1

Next tactic:
simp [heq1]
theorem empty_of_word_prod_eq_one {w : Word H} (h : lift f w.prod = 1) : w = Word.empty := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
w : Word H
h : (lift f) (Word.prod w) = 1
⊢ w = Word.empty

Next tactic:
by_contra hnotempty
theorem empty_of_word_prod_eq_one {w : Word H} (h : lift f w.prod = 1) : w = Word.empty := by
  by_contra hnotempty
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
w : Word H
h : (lift f) (Word.prod w) = 1
hnotempty : ¬w = Word.empty
⊢ False

Next tactic:
obtain ⟨i, j, w, rfl⟩ := NeWord.of_word w hnotempty
theorem empty_of_word_prod_eq_one {w : Word H} (h : lift f w.prod = 1) : w = Word.empty := by
  by_contra hnotempty
  obtain ⟨i, j, w, rfl⟩ := NeWord.of_word w hnotempty
  

Proof state:
case intro.intro.intro
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
i j : ι
w : NeWord H i j
h : (lift f) (Word.prod (NeWord.toWord w)) = 1
hnotempty : ¬NeWord.toWord w = Word.empty
⊢ False

Next tactic:
exact lift_word_prod_nontrivial_of_not_empty f hcard X hXnonempty hXdisj hpp w h
/-- 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) := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
⊢ Function.Injective ⇑(lift f)

Next tactic:
classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    rw [(CoprodI.Word.equiv).forall_congr_left']
    · intro w Heq
      dsimp [Word.equiv] at *
      · rw [empty_of_word_prod_eq_one f hcard X hXnonempty hXdisj hpp Heq]
        rfl
/-- 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) := by
  classical
    

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
⊢ Function.Injective ⇑(lift f)

Next tactic:
apply (injective_iff_map_eq_one (lift f)).mpr
/-- 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) := by
  classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
⊢ ∀ (a : CoprodI fun i => H i), (lift f) a = 1 → a = 1

Next tactic:
rw [(CoprodI.Word.equiv).forall_congr_left']
/-- 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) := by
  classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    rw [(CoprodI.Word.equiv).forall_congr_left']
    · 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
⊢ ∀ (y : Word fun i => H i), (lift f) (Word.equiv.symm y) = 1 → Word.equiv.symm y = 1

Next tactic:
intro w Heq
/-- 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) := by
  classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    rw [(CoprodI.Word.equiv).forall_congr_left']
    · intro w Heq
      

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), h ≠ 1 → (f i) h • X j ⊆ X i
w : Word fun i => H i
Heq : (lift f) (Word.equiv.symm w) = 1
⊢ Word.equiv.symm w = 1

Next tactic:
dsimp [Word.equiv] at *
/-- 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) := by
  classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    rw [(CoprodI.Word.equiv).forall_congr_left']
    · intro w Heq
      dsimp [Word.equiv] at *
      · 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), ¬h = 1 → (f i) h • X j ⊆ X i
w : Word fun i => H i
Heq : (lift f) (Word.prod w) = 1
⊢ Word.prod w = 1

Next tactic:
rw [empty_of_word_prod_eq_one f hcard X hXnonempty hXdisj hpp Heq]
/-- 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) := by
  classical
    apply (injective_iff_map_eq_one (lift f)).mpr
    rw [(CoprodI.Word.equiv).forall_congr_left']
    · intro w Heq
      dsimp [Word.equiv] at *
      · rw [empty_of_word_prod_eq_one f hcard X hXnonempty hXdisj hpp Heq]
        

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝⁴ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝³ : Monoid N
hnontriv : Nontrivial ι
G : Type u_4
inst✝² : Group G
H : ι → Type u_5
inst✝¹ : (i : ι) → Group (H i)
f : (i : ι) → H i →* G
hcard : 3 ≤ #ι ∨ ∃ i, 3 ≤ #(H i)
α : Type u_6
inst✝ : MulAction G α
X : ι → Set α
hXnonempty : ∀ (i : ι), Set.Nonempty (X i)
hXdisj : Pairwise fun i j => Disjoint (X i) (X j)
hpp : Pairwise fun i j => ∀ (h : H i), ¬h = 1 → (f i) h • X j ⊆ X i
w : Word fun i => H i
Heq : (lift f) (Word.prod w) = 1
⊢ Word.prod Word.empty = 1

Next tactic:
rfl
/-- 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) :=
  ⟨MulEquiv.symm <| MonoidHom.toMulEquiv
    (FreeGroup.lift fun x : Σ i, X i => CoprodI.of (B x.1 x.2))
    (CoprodI.lift fun i : ι => (B i).lift fun x : X i =>
              FreeGroup.of (⟨i, x⟩ : Σ i, X i))
    (by 

Proof state:
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝² : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
ι : Type u_4
X : ι → Type u_5
G : ι → Type u_6
inst✝ : (i : ι) → Group (G i)
B : (i : ι) → FreeGroupBasis (X i) (G i)
⊢ MonoidHom.comp (lift fun i => (FreeGroupBasis.lift (B i)) fun x => FreeGroup.of { fst := i, snd := x })
      (FreeGroup.lift fun x => of ((B x.fst) x.snd)) =
    MonoidHom.id (FreeGroup ((i : ι) × X i))

Next tactic:
ext
/-- 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) :=
  ⟨MulEquiv.symm <| MonoidHom.toMulEquiv
    (FreeGroup.lift fun x : Σ i, X i => CoprodI.of (B x.1 x.2))
    (CoprodI.lift fun i : ι => (B i).lift fun x : X i =>
              FreeGroup.of (⟨i, x⟩ : Σ i, X i))
    (by ext; 

Proof state:
case h
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝² : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
ι : Type u_4
X : ι → Type u_5
G : ι → Type u_6
inst✝ : (i : ι) → Group (G i)
B : (i : ι) → FreeGroupBasis (X i) (G i)
a✝ : (i : ι) × X i
⊢ (MonoidHom.comp (lift fun i => (FreeGroupBasis.lift (B i)) fun x => FreeGroup.of { fst := i, snd := x })
        (FreeGroup.lift fun x => of ((B x.fst) x.snd)))
      (FreeGroup.of a✝) =
    (MonoidHom.id (FreeGroup ((i : ι) × X i))) (FreeGroup.of a✝)

Next tactic:
simp
/-- 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) :=
  ⟨MulEquiv.symm <| MonoidHom.toMulEquiv
    (FreeGroup.lift fun x : Σ i, X i => CoprodI.of (B x.1 x.2))
    (CoprodI.lift fun i : ι => (B i).lift fun x : X i =>
              FreeGroup.of (⟨i, x⟩ : Σ i, X i))
    (by ext; simp)
    (by 

Proof state:
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝² : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
ι : Type u_4
X : ι → Type u_5
G : ι → Type u_6
inst✝ : (i : ι) → Group (G i)
B : (i : ι) → FreeGroupBasis (X i) (G i)
⊢ MonoidHom.comp (FreeGroup.lift fun x => of ((B x.fst) x.snd))
      (lift fun i => (FreeGroupBasis.lift (B i)) fun x => FreeGroup.of { fst := i, snd := x }) =
    MonoidHom.id (CoprodI G)

Next tactic:
ext1 i
/-- 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) :=
  ⟨MulEquiv.symm <| MonoidHom.toMulEquiv
    (FreeGroup.lift fun x : Σ i, X i => CoprodI.of (B x.1 x.2))
    (CoprodI.lift fun i : ι => (B i).lift fun x : X i =>
              FreeGroup.of (⟨i, x⟩ : Σ i, X i))
    (by ext; simp)
    (by ext1 i; 

Proof state:
case h
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝² : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
ι : Type u_4
X : ι → Type u_5
G : ι → Type u_6
inst✝ : (i : ι) → Group (G i)
B : (i : ι) → FreeGroupBasis (X i) (G i)
i : ι
⊢ MonoidHom.comp
      (MonoidHom.comp (FreeGroup.lift fun x => of ((B x.fst) x.snd))
        (lift fun i => (FreeGroupBasis.lift (B i)) fun x => FreeGroup.of { fst := i, snd := x }))
      of =
    MonoidHom.comp (MonoidHom.id (CoprodI G)) of

Next tactic:
apply (B i).ext_hom
/-- 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) :=
  ⟨MulEquiv.symm <| MonoidHom.toMulEquiv
    (FreeGroup.lift fun x : Σ i, X i => CoprodI.of (B x.1 x.2))
    (CoprodI.lift fun i : ι => (B i).lift fun x : X i =>
              FreeGroup.of (⟨i, x⟩ : Σ i, X i))
    (by ext; simp)
    (by ext1 i; apply (B i).ext_hom; 

Proof state:
case h.h
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝² : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
ι : Type u_4
X : ι → Type u_5
G : ι → Type u_6
inst✝ : (i : ι) → Group (G i)
B : (i : ι) → FreeGroupBasis (X i) (G i)
i : ι
⊢ ∀ (i_1 : X i),
    (MonoidHom.comp
          (MonoidHom.comp (FreeGroup.lift fun x => of ((B x.fst) x.snd))
            (lift fun i => (FreeGroupBasis.lift (B i)) fun x => FreeGroup.of { fst := i, snd := x }))
          of)
        ((B i) i_1) =
      (MonoidHom.comp (MonoidHom.id (CoprodI G)) of) ((B i) i_1)

Next tactic:
simp
/-- 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 := by
  

Proof state:
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ FreeGroup ι ≃* CoprodI fun x => FreeGroup Unit

Next tactic:
refine' MonoidHom.toMulEquiv _ _ _ _
/-- 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 := by
  refine' MonoidHom.toMulEquiv _ _ _ _
  

Proof state:
case refine'_1
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ FreeGroup ι →* CoprodI fun x => FreeGroup Unit
case refine'_2
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ (CoprodI fun x => FreeGroup Unit) →* FreeGroup ι
case refine'_3
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ MonoidHom.comp ?refine'_2 ?refine'_1 = MonoidHom.id (FreeGroup ι)
case refine'_4
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ MonoidHom.comp ?refine'_1 ?refine'_2 = MonoidHom.id (CoprodI fun x => FreeGroup Unit)

Next tactic:
exact FreeGroup.lift fun i => @CoprodI.of ι _ _ i (FreeGroup.of Unit.unit)
/-- 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 := by
  refine' MonoidHom.toMulEquiv _ _ _ _
  exact FreeGroup.lift fun i => @CoprodI.of ι _ _ i (FreeGroup.of Unit.unit)
  

Proof state:
case refine'_2
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ (CoprodI fun x => FreeGroup Unit) →* FreeGroup ι
case refine'_3
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ MonoidHom.comp ?refine'_2 (FreeGroup.lift fun i => of (FreeGroup.of ())) = MonoidHom.id (FreeGroup ι)
case refine'_4
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ MonoidHom.comp (FreeGroup.lift fun i => of (FreeGroup.of ())) ?refine'_2 =
    MonoidHom.id (CoprodI fun x => FreeGroup Unit)

Next tactic:
exact CoprodI.lift fun i => FreeGroup.lift fun _ => FreeGroup.of i
/-- 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 := by
  refine' MonoidHom.toMulEquiv _ _ _ _
  exact FreeGroup.lift fun i => @CoprodI.of ι _ _ i (FreeGroup.of Unit.unit)
  exact CoprodI.lift fun i => FreeGroup.lift fun _ => FreeGroup.of i
  · 

Proof state:
case refine'_3
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
⊢ MonoidHom.comp (lift fun i => FreeGroup.lift fun x => FreeGroup.of i) (FreeGroup.lift fun i => of (FreeGroup.of ())) =
    MonoidHom.id (FreeGroup ι)

Next tactic:
ext
/-- 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 := by
  refine' MonoidHom.toMulEquiv _ _ _ _
  exact FreeGroup.lift fun i => @CoprodI.of ι _ _ i (FreeGroup.of Unit.unit)
  exact CoprodI.lift fun i => FreeGroup.lift fun _ => FreeGroup.of i
  · ext; 

Proof state:
case refine'_3.h
ι✝ : Type u_1
M : ι✝ → Type u_2
inst✝¹ : (i : ι✝) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
ι : Type u_1
a✝ : ι
⊢ (MonoidHom.comp (lift fun i => FreeGroup.lift fun x => FreeGroup.of i) (FreeGroup.lift fun i => of (FreeGroup.of ())))
      (FreeGroup.of a✝) =
    (MonoidHom.id (FreeGroup ι)) (FreeGroup.of a✝)

Next tactic:
simp