l3lab/ntp-mathlib huggingface dataset:
@[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 := by
  let S : Submonoid (CoprodI M) :=
    { carrier := setOf C
      mul_mem' := h_mul _ _
      one_mem' := h_one }
  have : C _ := Subtype.prop (lift (fun i => of.codRestrict S (h_of i)) m)
  convert this
  

Proof state:
case h.e'_1
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
C : CoprodI M → Prop
m : CoprodI M
h_one : C 1
h_of : ∀ (i : ι) (m : M i), C (of m)
h_mul : ∀ (x y : CoprodI M), C x → C y → C (x * y)
S : Submonoid (CoprodI M) :=
  { toSubsemigroup := { carrier := setOf C, mul_mem' := (_ : ∀ {a b : CoprodI M}, C a → C b → C (a * b)) },
    one_mem' := h_one }
this : C ↑((lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))) m)
⊢ m = ↑((lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))) m)

Next tactic:
change MonoidHom.id _ m = S.subtype.comp _ m
@[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 := by
  let S : Submonoid (CoprodI M) :=
    { carrier := setOf C
      mul_mem' := h_mul _ _
      one_mem' := h_one }
  have : C _ := Subtype.prop (lift (fun i => of.codRestrict S (h_of i)) m)
  convert this
  change MonoidHom.id _ m = S.subtype.comp _ m
  

Proof state:
case h.e'_1
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
C : CoprodI M → Prop
m : CoprodI M
h_one : C 1
h_of : ∀ (i : ι) (m : M i), C (of m)
h_mul : ∀ (x y : CoprodI M), C x → C y → C (x * y)
S : Submonoid (CoprodI M) :=
  { toSubsemigroup := { carrier := setOf C, mul_mem' := (_ : ∀ {a b : CoprodI M}, C a → C b → C (a * b)) },
    one_mem' := h_one }
this : C ↑((lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))) m)
⊢ (MonoidHom.id (CoprodI M)) m =
    (MonoidHom.comp (Submonoid.subtype S) (lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m)))) m

Next tactic:
congr
@[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 := by
  let S : Submonoid (CoprodI M) :=
    { carrier := setOf C
      mul_mem' := h_mul _ _
      one_mem' := h_one }
  have : C _ := Subtype.prop (lift (fun i => of.codRestrict S (h_of i)) m)
  convert this
  change MonoidHom.id _ m = S.subtype.comp _ m
  congr
  

Proof state:
case h.e'_1.e_a
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
C : CoprodI M → Prop
m : CoprodI M
h_one : C 1
h_of : ∀ (i : ι) (m : M i), C (of m)
h_mul : ∀ (x y : CoprodI M), C x → C y → C (x * y)
S : Submonoid (CoprodI M) :=
  { toSubsemigroup := { carrier := setOf C, mul_mem' := (_ : ∀ {a b : CoprodI M}, C a → C b → C (a * b)) },
    one_mem' := h_one }
this : C ↑((lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))) m)
⊢ MonoidHom.id (CoprodI M) =
    MonoidHom.comp (Submonoid.subtype S) (lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m)))

Next tactic:
ext i
@[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 := by
  let S : Submonoid (CoprodI M) :=
    { carrier := setOf C
      mul_mem' := h_mul _ _
      one_mem' := h_one }
  have : C _ := Subtype.prop (lift (fun i => of.codRestrict S (h_of i)) m)
  convert this
  change MonoidHom.id _ m = S.subtype.comp _ m
  congr
  ext i
  

Proof state:
case h.e'_1.e_a.h.h
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
C : CoprodI M → Prop
m : CoprodI M
h_one : C 1
h_of : ∀ (i : ι) (m : M i), C (of m)
h_mul : ∀ (x y : CoprodI M), C x → C y → C (x * y)
S : Submonoid (CoprodI M) :=
  { toSubsemigroup := { carrier := setOf C, mul_mem' := (_ : ∀ {a b : CoprodI M}, C a → C b → C (a * b)) },
    one_mem' := h_one }
this : C ↑((lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))) m)
i : ι
x✝ : M i
⊢ (MonoidHom.comp (MonoidHom.id (CoprodI M)) of) x✝ =
    (MonoidHom.comp
        (MonoidHom.comp (Submonoid.subtype S) (lift fun i => MonoidHom.codRestrict of S (_ : ∀ (m : M i), C (of m))))
        of)
      x✝

Next tactic:
rfl
theorem of_leftInverse [DecidableEq ι] (i : ι) :
    Function.LeftInverse (lift <| Pi.mulSingle i (MonoidHom.id (M i))) of := fun x => by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : DecidableEq ι
i : ι
x : M i
⊢ (lift (Pi.mulSingle i (MonoidHom.id (M i)))) (of x) = x

Next tactic:
simp only [lift_of, Pi.mulSingle_eq_same, MonoidHom.id_apply]
theorem of_injective (i : ι) : Function.Injective (of : M i →* _) := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
i : ι
⊢ Function.Injective ⇑of

Next tactic:
classical exact (of_leftInverse i).injective
theorem of_injective (i : ι) : Function.Injective (of : M i →* _) := by
  classical 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝¹ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝ : Monoid N
i : ι
⊢ Function.Injective ⇑of

Next tactic:
exact (of_leftInverse i).injective
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
⊢ MonoidHom.mrange (lift f) ≤ s

Next tactic:
rintro _ ⟨x, rfl⟩
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  

Proof state:
case intro
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
x : CoprodI fun i => M i
⊢ (lift f) x ∈ s

Next tactic:
induction' x using CoprodI.induction_on with i x x y hx hy
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · 

Proof state:
case intro.h_one
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
⊢ (lift f) 1 ∈ s

Next tactic:
exact s.one_mem
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · 

Proof state:
case intro.h_of
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
i : ι
x : M i
⊢ (lift f) (of x) ∈ s

Next tactic:
simp only [lift_of, SetLike.mem_coe]
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    

Proof state:
case intro.h_of
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
i : ι
x : M i
⊢ (f i) x ∈ s

Next tactic:
exact h i (Set.mem_range_self x)
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    exact h i (Set.mem_range_self x)
  · 

Proof state:
case intro.h_mul
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
x y : CoprodI fun i => M i
hx : (lift f) x ∈ s
hy : (lift f) y ∈ s
⊢ (lift f) (x * y) ∈ s

Next tactic:
simp only [map_mul, SetLike.mem_coe]
theorem lift_mrange_le {N} [Monoid N] (f : ∀ i, M i →* N) {s : Submonoid N}
    (h : ∀ i, MonoidHom.mrange (f i) ≤ s) : MonoidHom.mrange (lift f) ≤ s := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    exact h i (Set.mem_range_self x)
  · simp only [map_mul, SetLike.mem_coe]
    

Proof state:
case intro.h_mul
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
s : Submonoid N
h : ∀ (i : ι), MonoidHom.mrange (f i) ≤ s
x y : CoprodI fun i => M i
hx : (lift f) x ∈ s
hy : (lift f) y ∈ s
⊢ (lift f) x * (lift f) y ∈ s

Next tactic:
exact s.mul_mem hx hy
theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
⊢ MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i)

Next tactic:
apply le_antisymm (lift_mrange_le f fun i => le_iSup (fun i => MonoidHom.mrange (f i)) i)
theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) := by
  apply le_antisymm (lift_mrange_le f fun i => le_iSup (fun i => MonoidHom.mrange (f i)) i)
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
⊢ ⨆ i, MonoidHom.mrange (f i) ≤ MonoidHom.mrange (lift f)

Next tactic:
apply iSup_le _
theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) := by
  apply le_antisymm (lift_mrange_le f fun i => le_iSup (fun i => MonoidHom.mrange (f i)) i)
  apply iSup_le _
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
⊢ ∀ (i : ι), MonoidHom.mrange (f i) ≤ MonoidHom.mrange (lift f)

Next tactic:
rintro i _ ⟨x, rfl⟩
theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) := by
  apply le_antisymm (lift_mrange_le f fun i => le_iSup (fun i => MonoidHom.mrange (f i)) i)
  apply iSup_le _
  rintro i _ ⟨x, rfl⟩
  

Proof state:
case intro
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
i : ι
x : M i
⊢ (f i) x ∈ MonoidHom.mrange (lift f)

Next tactic:
exact ⟨of x, by simp only [lift_of]⟩
theorem mrange_eq_iSup {N} [Monoid N] (f : ∀ i, M i →* N) :
    MonoidHom.mrange (lift f) = ⨆ i, MonoidHom.mrange (f i) := by
  apply le_antisymm (lift_mrange_le f fun i => le_iSup (fun i => MonoidHom.mrange (f i)) i)
  apply iSup_le _
  rintro i _ ⟨x, rfl⟩
  exact ⟨of x, by 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝¹ : Monoid N✝
N : Type u_4
inst✝ : Monoid N
f : (i : ι) → M i →* N
i : ι
x : M i
⊢ (lift f) (of x) = (f i) x

Next tactic:
simp only [lift_of]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
⊢ ∀ (a : CoprodI G), a⁻¹ * a = 1

Next tactic:
intro m
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
m : CoprodI G
⊢ m⁻¹ * m = 1

Next tactic:
rw [inv_def]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
m : CoprodI G
⊢ MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) m) *
      m =
    1

Next tactic:
induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      | h_of m ih =>
        change of _⁻¹ * of _ = 1
        rw [← of.map_mul, mul_left_inv, of.map_one]
      | h_mul x y ihx ihy =>
        rw [MonoidHom.map_mul, MulOpposite.unop_mul, mul_assoc, ← mul_assoc _ x y, ihx, one_mul,
          ihy]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      

Proof state:
case h_one
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
⊢ MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) 1) *
      1 =
    1

Next tactic:
| h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => 

Proof state:
case h_one
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
⊢ MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) 1) *
      1 =
    1

Next tactic:
rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      

Proof state:
case h_of
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
m : ι
ih : G m
⊢ MulOpposite.unop
        ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) (of ih)) *
      of ih =
    1

Next tactic:
| h_of m ih =>
        change of _⁻¹ * of _ = 1
        rw [← of.map_mul, mul_left_inv, of.map_one]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      | h_of m ih =>
        

Proof state:
case h_of
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
m : ι
ih : G m
⊢ MulOpposite.unop
        ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) (of ih)) *
      of ih =
    1

Next tactic:
change of _⁻¹ * of _ = 1
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      | h_of m ih =>
        change of _⁻¹ * of _ = 1
        

Proof state:
case h_of
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
m : ι
ih : G m
⊢ of { fst := m, snd := ih }.snd⁻¹ * of ih = 1

Next tactic:
rw [← of.map_mul, mul_left_inv, of.map_one]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      | h_of m ih =>
        change of _⁻¹ * of _ = 1
        rw [← of.map_mul, mul_left_inv, of.map_one]
      

Proof state:
case h_mul
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
x y : CoprodI G
ihx :
  MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) x) *
      x =
    1
ihy :
  MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) y) *
      y =
    1
⊢ MulOpposite.unop
        ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) (x * y)) *
      (x * y) =
    1

Next tactic:
| h_mul x y ihx ihy =>
        rw [MonoidHom.map_mul, MulOpposite.unop_mul, mul_assoc, ← mul_assoc _ x y, ihx, one_mul,
          ihy]
instance : Group (CoprodI G) :=
  { mul_left_inv := by
      intro m
      rw [inv_def]
      induction m using CoprodI.induction_on with
      | h_one => rw [MonoidHom.map_one, MulOpposite.unop_one, one_mul]
      | h_of m ih =>
        change of _⁻¹ * of _ = 1
        rw [← of.map_mul, mul_left_inv, of.map_one]
      | h_mul x y ihx ihy =>
        

Proof state:
case h_mul
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
G : ι → Type u_4
inst✝ : (i : ι) → Group (G i)
x y : CoprodI G
ihx :
  MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) x) *
      x =
    1
ihy :
  MulOpposite.unop ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) y) *
      y =
    1
⊢ MulOpposite.unop
        ((lift fun i => MonoidHom.comp (MonoidHom.op of) (MulEquiv.toMonoidHom (MulEquiv.inv' (G i)))) (x * y)) *
      (x * y) =
    1

Next tactic:
rw [MonoidHom.map_mul, MulOpposite.unop_mul, mul_assoc, ← mul_assoc _ x y, ihx, one_mul,
          ihy]
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 := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
⊢ MonoidHom.range (lift f) ≤ s

Next tactic:
rintro _ ⟨x, rfl⟩
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 := by
  rintro _ ⟨x, rfl⟩
  

Proof state:
case intro
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
x : CoprodI fun i => G i
⊢ (lift f) x ∈ s

Next tactic:
induction' x using CoprodI.induction_on with i x x y hx hy
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 := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · 

Proof state:
case intro.h_one
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
⊢ (lift f) 1 ∈ s

Next tactic:
exact s.one_mem
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 := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · 

Proof state:
case intro.h_of
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
i : ι
x : G i
⊢ (lift f) (of x) ∈ s

Next tactic:
simp only [lift_of, SetLike.mem_coe]
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 := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    

Proof state:
case intro.h_of
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
i : ι
x : G i
⊢ (f i) x ∈ s

Next tactic:
exact h i (Set.mem_range_self x)
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 := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    exact h i (Set.mem_range_self x)
  · 

Proof state:
case intro.h_mul
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
x y : CoprodI fun i => G i
hx : (lift f) x ∈ s
hy : (lift f) y ∈ s
⊢ (lift f) (x * y) ∈ s

Next tactic:
simp only [map_mul, SetLike.mem_coe]
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 := by
  rintro _ ⟨x, rfl⟩
  induction' x using CoprodI.induction_on with i x x y hx hy
  · exact s.one_mem
  · simp only [lift_of, SetLike.mem_coe]
    exact h i (Set.mem_range_self x)
  · simp only [map_mul, SetLike.mem_coe]
    

Proof state:
case intro.h_mul
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
s : Subgroup N
h : ∀ (i : ι), MonoidHom.range (f i) ≤ s
x y : CoprodI fun i => G i
hx : (lift f) x ∈ s
hy : (lift f) y ∈ s
⊢ (lift f) x * (lift f) y ∈ s

Next tactic:
exact s.mul_mem hx hy
theorem range_eq_iSup {N} [Group N] (f : ∀ i, G i →* N) : (lift f).range = ⨆ i, (f i).range := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
⊢ MonoidHom.range (lift f) = ⨆ i, MonoidHom.range (f i)

Next tactic:
apply le_antisymm (lift_range_le _ f fun i => le_iSup (fun i => MonoidHom.range (f i)) i)
theorem range_eq_iSup {N} [Group N] (f : ∀ i, G i →* N) : (lift f).range = ⨆ i, (f i).range := by
  apply le_antisymm (lift_range_le _ f fun i => le_iSup (fun i => MonoidHom.range (f i)) i)
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
⊢ ⨆ i, MonoidHom.range (f i) ≤ MonoidHom.range (lift f)

Next tactic:
apply iSup_le _
theorem range_eq_iSup {N} [Group N] (f : ∀ i, G i →* N) : (lift f).range = ⨆ i, (f i).range := by
  apply le_antisymm (lift_range_le _ f fun i => le_iSup (fun i => MonoidHom.range (f i)) i)
  apply iSup_le _
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N✝ : Type u_3
inst✝² : Monoid N✝
G : ι → Type u_4
inst✝¹ : (i : ι) → Group (G i)
N : Type u_5
inst✝ : Group N
f : (i : ι) → G i →* N
⊢ ∀ (i : ι), MonoidHom.range (f i) ≤ MonoidHom.range (lift f)

Next tactic:
rintro i _ ⟨x, rfl⟩