l3lab/ntp-mathlib huggingface dataset:
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
⊢ OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } (x * y) =
    OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } x *
      OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } y

Next tactic:
simp only
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
⊢ (lift ⇑f) (x * y) = (lift ⇑f) x * (lift ⇑f) y

Next tactic:
refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
⊢ (lift ⇑f) (x * 0) = (lift ⇑f) x * (lift ⇑f) 0

Next tactic:
simp only [mul_zero, map_zero]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · 

Proof state:
case refine'_1
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 : α
⊢ (lift ⇑f) (x * of L2) = (lift ⇑f) x * (lift ⇑f) (of L2)

Next tactic:
refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 : α
⊢ (lift ⇑f) (0 * of L2) = (lift ⇑f) 0 * (lift ⇑f) (of L2)

Next tactic:
simp only [zero_mul, map_zero]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · 

Proof state:
case refine'_1.refine'_1
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 L1 : α
⊢ (lift ⇑f) (of L1 * of L2) = (lift ⇑f) (of L1) * (lift ⇑f) (of L2)

Next tactic:
simp_rw [of_mul_of, lift.of]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          

Proof state:
case refine'_1.refine'_1
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 L1 : α
⊢ f (L1 * L2) = f L1 * f L2

Next tactic:
exact f.map_mul _ _
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · 

Proof state:
case refine'_1.refine'_2
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 L1 : α
ih : (lift ⇑f) (of L1 * of L2) = (lift ⇑f) (of L1) * (lift ⇑f) (of L2)
⊢ (lift ⇑f) (-of L1 * of L2) = (lift ⇑f) (-of L1) * (lift ⇑f) (of L2)

Next tactic:
simp_rw [neg_mul, map_neg, neg_mul]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          

Proof state:
case refine'_1.refine'_2
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 L1 : α
ih : (lift ⇑f) (of L1 * of L2) = (lift ⇑f) (of L1) * (lift ⇑f) (of L2)
⊢ -(lift ⇑f) (of L1 * of L2) = -((lift ⇑f) (of L1) * (lift ⇑f) (of L2))

Next tactic:
exact congr_arg Neg.neg ih
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · 

Proof state:
case refine'_1.refine'_3
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 : α
⊢ ∀ (x y : FreeAbelianGroup α),
    (lift ⇑f) (x * of L2) = (lift ⇑f) x * (lift ⇑f) (of L2) →
      (lift ⇑f) (y * of L2) = (lift ⇑f) y * (lift ⇑f) (of L2) →
        (lift ⇑f) ((x + y) * of L2) = (lift ⇑f) (x + y) * (lift ⇑f) (of L2)

Next tactic:
intro x1 x2 ih1 ih2
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          

Proof state:
case refine'_1.refine'_3
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 : α
x1 x2 : FreeAbelianGroup α
ih1 : (lift ⇑f) (x1 * of L2) = (lift ⇑f) x1 * (lift ⇑f) (of L2)
ih2 : (lift ⇑f) (x2 * of L2) = (lift ⇑f) x2 * (lift ⇑f) (of L2)
⊢ (lift ⇑f) ((x1 + x2) * of L2) = (lift ⇑f) (x1 + x2) * (lift ⇑f) (of L2)

Next tactic:
simp only [add_mul, map_add, ih1, ih2]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · 

Proof state:
case refine'_2
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
L2 : α
ih : (lift ⇑f) (x * of L2) = (lift ⇑f) x * (lift ⇑f) (of L2)
⊢ (lift ⇑f) (x * -of L2) = (lift ⇑f) x * (lift ⇑f) (-of L2)

Next tactic:
rw [mul_neg, map_neg, map_neg, mul_neg, ih]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · 

Proof state:
case refine'_3
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y : FreeAbelianGroup α
⊢ ∀ (x_1 y : FreeAbelianGroup α),
    (lift ⇑f) (x * x_1) = (lift ⇑f) x * (lift ⇑f) x_1 →
      (lift ⇑f) (x * y) = (lift ⇑f) x * (lift ⇑f) y → (lift ⇑f) (x * (x_1 + y)) = (lift ⇑f) x * (lift ⇑f) (x_1 + y)

Next tactic:
intro y1 y2 ih1 ih2
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · intro y1 y2 ih1 ih2
        

Proof state:
case refine'_3
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
src✝ : FreeAbelianGroup α →+ R := lift ⇑f
x y y1 y2 : FreeAbelianGroup α
ih1 : (lift ⇑f) (x * y1) = (lift ⇑f) x * (lift ⇑f) y1
ih2 : (lift ⇑f) (x * y2) = (lift ⇑f) x * (lift ⇑f) y2
⊢ (lift ⇑f) (x * (y1 + y2)) = (lift ⇑f) x * (lift ⇑f) (y1 + y2)

Next tactic:
rw [mul_add, map_add, map_add, mul_add, ih1, ih2]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · intro y1 y2 ih1 ih2
        rw [mul_add, map_add, map_add, mul_add, ih1, ih2] }
  invFun F := MonoidHom.comp (↑F) ofMulHom
  left_inv f := MonoidHom.ext <| by
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
f : α →* R
⊢ ∀ (x : α),
    ((fun F => MonoidHom.comp (↑F) ofMulHom)
          ((fun f =>
              let src := lift ⇑f;
              {
                toMonoidHom :=
                  { toOneHom := { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) },
                    map_mul' :=
                      (_ :
                        ∀ (x y : FreeAbelianGroup α),
                          OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } (x * y) =
                            OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } x *
                              OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } y) },
                map_zero' := (_ : ZeroHom.toFun (↑src) 0 = 0),
                map_add' :=
                  (_ :
                    ∀ (x y : FreeAbelianGroup α),
                      ZeroHom.toFun (↑src) (x + y) = ZeroHom.toFun (↑src) x + ZeroHom.toFun (↑src) y) })
            f))
        x =
      f x

Next tactic:
simp only [RingHom.coe_monoidHom_mk, MonoidHom.coe_comp, MonoidHom.coe_mk, OneHom.coe_mk,
      ofMulHom_coe, Function.comp_apply, lift.of, forall_const]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · intro y1 y2 ih1 ih2
        rw [mul_add, map_add, map_add, mul_add, ih1, ih2] }
  invFun F := MonoidHom.comp (↑F) ofMulHom
  left_inv f := MonoidHom.ext <| by
    simp only [RingHom.coe_monoidHom_mk, MonoidHom.coe_comp, MonoidHom.coe_mk, OneHom.coe_mk,
      ofMulHom_coe, Function.comp_apply, lift.of, forall_const]
  right_inv F := RingHom.coe_addMonoidHom_injective <| by
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
F : FreeAbelianGroup α →+* R
⊢ (fun f => ↑f)
      ((fun f =>
          let src := lift ⇑f;
          {
            toMonoidHom :=
              { toOneHom := { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) },
                map_mul' :=
                  (_ :
                    ∀ (x y : FreeAbelianGroup α),
                      OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } (x * y) =
                        OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } x *
                          OneHom.toFun { toFun := ⇑(lift ⇑f), map_one' := (_ : (lift ⇑f) (of 1) = 1) } y) },
            map_zero' := (_ : ZeroHom.toFun (↑src) 0 = 0),
            map_add' :=
              (_ :
                ∀ (x y : FreeAbelianGroup α),
                  ZeroHom.toFun (↑src) (x + y) = ZeroHom.toFun (↑src) x + ZeroHom.toFun (↑src) y) })
        ((fun F => MonoidHom.comp (↑F) ofMulHom) F)) =
    (fun f => ↑f) F

Next tactic:
simp only
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · intro y1 y2 ih1 ih2
        rw [mul_add, map_add, map_add, mul_add, ih1, ih2] }
  invFun F := MonoidHom.comp (↑F) ofMulHom
  left_inv f := MonoidHom.ext <| by
    simp only [RingHom.coe_monoidHom_mk, MonoidHom.coe_comp, MonoidHom.coe_mk, OneHom.coe_mk,
      ofMulHom_coe, Function.comp_apply, lift.of, forall_const]
  right_inv F := RingHom.coe_addMonoidHom_injective <| by
    simp only
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
F : FreeAbelianGroup α →+* R
⊢ ↑{
        toMonoidHom :=
          {
            toOneHom :=
              { toFun := ⇑(lift ⇑(MonoidHom.comp (↑F) ofMulHom)),
                map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) },
            map_mul' :=
              (_ :
                ∀ (x y : FreeAbelianGroup α),
                  OneHom.toFun
                      { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                        map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                      (x * y) =
                    OneHom.toFun
                        { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                          map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                        x *
                      OneHom.toFun
                        { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                          map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                        y) },
        map_zero' := (_ : ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) 0 = 0),
        map_add' :=
          (_ :
            ∀ (x y : FreeAbelianGroup α),
              ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) (x + y) =
                ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) x +
                  ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) y) } =
    ↑F

Next tactic:
rw [← lift.apply_symm_apply (↑F : FreeAbelianGroup α →+ R)]
/-- If `f` preserves multiplication, then so does `lift f`. -/
def liftMonoid : (α →* R) ≃ (FreeAbelianGroup α →+* R) where
  toFun f := { lift f with
    toFun := lift f
    map_one' := (lift.of f _).trans f.map_one
    map_mul' := fun x y ↦ by
      simp only
      refine' FreeAbelianGroup.induction_on y
          (by simp only [mul_zero, map_zero]) (fun L2 ↦ _) (fun L2 ih ↦ _) _
      · refine' FreeAbelianGroup.induction_on x
            (by simp only [zero_mul, map_zero]) (fun L1 ↦ _) (fun L1 ih ↦ _) _
        · simp_rw [of_mul_of, lift.of]
          exact f.map_mul _ _
        · simp_rw [neg_mul, map_neg, neg_mul]
          exact congr_arg Neg.neg ih
        · intro x1 x2 ih1 ih2
          simp only [add_mul, map_add, ih1, ih2]
      · rw [mul_neg, map_neg, map_neg, mul_neg, ih]
      · intro y1 y2 ih1 ih2
        rw [mul_add, map_add, map_add, mul_add, ih1, ih2] }
  invFun F := MonoidHom.comp (↑F) ofMulHom
  left_inv f := MonoidHom.ext <| by
    simp only [RingHom.coe_monoidHom_mk, MonoidHom.coe_comp, MonoidHom.coe_mk, OneHom.coe_mk,
      ofMulHom_coe, Function.comp_apply, lift.of, forall_const]
  right_inv F := RingHom.coe_addMonoidHom_injective <| by
    simp only
    rw [← lift.apply_symm_apply (↑F : FreeAbelianGroup α →+ R)]
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type u_1
inst✝¹ : Monoid α
inst✝ : Ring R
F : FreeAbelianGroup α →+* R
⊢ ↑{
        toMonoidHom :=
          {
            toOneHom :=
              { toFun := ⇑(lift ⇑(MonoidHom.comp (↑F) ofMulHom)),
                map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) },
            map_mul' :=
              (_ :
                ∀ (x y : FreeAbelianGroup α),
                  OneHom.toFun
                      { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                        map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                      (x * y) =
                    OneHom.toFun
                        { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                          map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                        x *
                      OneHom.toFun
                        { toFun := ⇑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)),
                          map_one' := (_ : (lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F)) (of 1) = 1) }
                        y) },
        map_zero' := (_ : ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) 0 = 0),
        map_add' :=
          (_ :
            ∀ (x y : FreeAbelianGroup α),
              ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) (x + y) =
                ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) x +
                  ZeroHom.toFun (↑(lift ⇑((fun F => MonoidHom.comp (↑F) ofMulHom) F))) y) } =
    lift (lift.symm ↑F)

Next tactic:
rfl
instance [CommMonoid α] : CommRing (FreeAbelianGroup α) :=
  { FreeAbelianGroup.ring α with
    mul_comm := fun x y ↦ by
      

Proof state:
α : Type u
β : Type v
γ : Type w
inst✝ : CommMonoid α
src✝ : Ring (FreeAbelianGroup α) := ring α
x y : FreeAbelianGroup α
⊢ x * y = y * x

Next tactic:
refine' FreeAbelianGroup.induction_on x (zero_mul y) _ _ _
instance [CommMonoid α] : CommRing (FreeAbelianGroup α) :=
  { FreeAbelianGroup.ring α with
    mul_comm := fun x y ↦ by
      refine' FreeAbelianGroup.induction_on x (zero_mul y) _ _ _
      · 

Proof state:
case refine'_1
α : Type u
β : Type v
γ : Type w
inst✝ : CommMonoid α
src✝ : Ring (FreeAbelianGroup α) := ring α
x y : FreeAbelianGroup α
⊢ ∀ (x : α), of x * y = y * of x

Next tactic:
intro s