l3lab/ntp-mathlib huggingface dataset:
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          

Proof state:
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| ↑(fS { val := ↑s₂ * r₃, property := hs₂r₃ })⁻¹ *
    (f (↑s₂ * r₃) * ↑(fS { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) })⁻¹)

Next tactic:
congr
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          

Proof state:
case a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| ↑(fS { val := ↑s₂ * r₃, property := hs₂r₃ })⁻¹
case a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| f (↑s₂ * r₃) * ↑(fS { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) })⁻¹

Next tactic:
· skip
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          · 

Proof state:
case a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| ↑(fS { val := ↑s₂ * r₃, property := hs₂r₃ })⁻¹

Next tactic:
skip
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          · skip
          

Proof state:
case a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| f (↑s₂ * r₃) * ↑(fS { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) })⁻¹

Next tactic:
congr
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          · skip
          congr
          

Proof state:
case a.a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| f (↑s₂ * r₃)
case a.a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| ↑(fS { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) })⁻¹

Next tactic:
rw [← h₃]
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          · skip
          congr
          rw [← h₃]
        

Proof state:
case a.a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
| ↑(fS { val := ↑s₂ * r₃, property := hs₂r₃ })⁻¹ *
    (f ↑(s₁ * s₃) * ↑(fS { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) })⁻¹)

Next tactic:
rw [hf, ← mul_assoc, ← h₃', Units.inv_mul]
/-- The universal lift from a ring homomorphism `f : R →+* T`, which maps elements in `S` to
units of `T`, to a ring homomorphism `R[S⁻¹] →+* T`. This extends the construction on
monoids. -/
def universalHom : R[S⁻¹] →+* T :=
  {
    universalMulHom f.toMonoidHom fS
      hf with
    map_zero' := by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) 0 = 0
      rw [OreLocalization.zero_def, universalMulHom_apply]
      simp
    map_add' := fun x y => by
      -- Porting note: `change` required because of new `Coe`
      change (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) (x + y)
        = (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) x
        + (universalMulHom f.toMonoidHom fS hf : R[S⁻¹] → T) y
      induction' x using OreLocalization.ind with r₁ s₁
      induction' y using OreLocalization.ind with r₂ s₂
      rcases oreDivAddChar' r₁ r₂ s₁ s₂ with ⟨r₃, s₃, h₃, h₃'⟩
      rw [h₃']
      clear h₃'
      simp only [universalMulHom_apply, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe]
      simp only [mul_inv_rev, MonoidHom.map_mul, RingHom.map_add, RingHom.map_mul, Units.val_mul]
      rw [add_mul, ← mul_assoc, mul_assoc (f r₁), hf, ← Units.val_mul]
      simp only [mul_one, mul_right_inv, Units.val_one]
      congr 1
      rw [mul_assoc]
      congr 1
      norm_cast at h₃
      have h₃' := Subtype.coe_eq_of_eq_mk h₃
      rw [← Units.val_mul, ← mul_inv_rev, ← fS.map_mul, h₃']
      have hs₂r₃ : ↑s₂ * r₃ ∈ S := by
        rw [← h₃]
        exact SetLike.coe_mem (s₁ * s₃)
      apply (Units.inv_mul_cancel_left (fS s₂) _).symm.trans
      conv_lhs =>
        congr
        · skip
        rw [← Units.mul_inv_cancel_left (fS ⟨s₂ * r₃, hs₂r₃⟩) (fS s₂), mul_assoc, mul_assoc]
        congr
        · skip
        rw [← hf, ← mul_assoc (f s₂), ← f.map_mul]
        conv =>
          congr
          · skip
          congr
          rw [← h₃]
        rw [hf, ← mul_assoc, ← h₃', Units.inv_mul]
      

Proof state:
case c.c.mk.mk.intro.e_a.e_a
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
src✝ : OreLocalization R S →* T := universalMulHom (↑f) fS hf
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
h₃ : ↑(s₁ * s₃) = ↑s₂ * r₃
h₃' : s₁ * s₃ = { val := ↑s₂ * r₃, property := (_ : ↑s₂ * r₃ ∈ ↑S) }
hs₂r₃ : ↑s₂ * r₃ ∈ S
⊢ ↑(fS s₂)⁻¹ * (↑(fS { val := ↑s₂ * r₃, property := hs₂r₃ }) * (1 * ↑(fS (s₁ * s₃))⁻¹)) = ↑(fS s₂)⁻¹

Next tactic:
rw [one_mul, ← h₃', Units.mul_inv, mul_one]
theorem universalHom_commutes {r : R} : universalHom f fS hf (numeratorHom r) = f r := by
  

Proof state:
R : Type u_1
inst✝² : Semiring R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Semiring T
f : R →+* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
r : R
⊢ (universalHom f fS hf) (numeratorHom r) = f r

Next tactic:
simp [numeratorHom_apply, universalHom_apply]
/-- Negation on the Ore localization is defined via negation on the numerator. -/
protected def neg : R[S⁻¹] → R[S⁻¹] :=
  liftExpand (fun (r : R) (s : S) => -r /ₒ s) fun r t s ht => by
    -- Porting note: `simp only []` required for beta reductions
    

Proof state:
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
r t : R
s : ↥S
ht : ↑s * t ∈ S
⊢ (fun r s => -r /ₒ s) r s = (fun r s => -r /ₒ s) (r * t) { val := ↑s * t, property := ht }

Next tactic:
simp only []
/-- Negation on the Ore localization is defined via negation on the numerator. -/
protected def neg : R[S⁻¹] → R[S⁻¹] :=
  liftExpand (fun (r : R) (s : S) => -r /ₒ s) fun r t s ht => by
    -- Porting note: `simp only []` required for beta reductions
    simp only []
    

Proof state:
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
r t : R
s : ↥S
ht : ↑s * t ∈ S
⊢ -r /ₒ s = -(r * t) /ₒ { val := ↑s * t, property := ht }

Next tactic:
rw [neg_mul_eq_neg_mul, ← OreLocalization.expand]
protected theorem add_left_neg (x : R[S⁻¹]) : -x + x = 0 := by
  

Proof state:
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
x : OreLocalization R S
⊢ -x + x = 0

Next tactic:
induction' x using OreLocalization.ind with r s
protected theorem add_left_neg (x : R[S⁻¹]) : -x + x = 0 := by
  induction' x using OreLocalization.ind with r s; 

Proof state:
case c
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
r : R
s : ↥S
⊢ -(r /ₒ s) + r /ₒ s = 0

Next tactic:
simp
theorem numeratorHom_inj (hS : S ≤ R⁰) : Function.Injective (numeratorHom : R → R[S⁻¹]) :=
  fun r₁ r₂ h => by
  

Proof state:
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
hS : S ≤ R⁰
r₁ r₂ : R
h : numeratorHom r₁ = numeratorHom r₂
⊢ r₁ = r₂

Next tactic:
rw [numeratorHom_apply, numeratorHom_apply, oreDiv_eq_iff] at h
theorem numeratorHom_inj (hS : S ≤ R⁰) : Function.Injective (numeratorHom : R → R[S⁻¹]) :=
  fun r₁ r₂ h => by
  rw [numeratorHom_apply, numeratorHom_apply, oreDiv_eq_iff] at h
  

Proof state:
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
hS : S ≤ R⁰
r₁ r₂ : R
h : ∃ u v, r₂ * ↑u = r₁ * v ∧ ↑1 * ↑u = ↑1 * v
⊢ r₁ = r₂

Next tactic:
rcases h with ⟨u, v, h₁, h₂⟩
theorem numeratorHom_inj (hS : S ≤ R⁰) : Function.Injective (numeratorHom : R → R[S⁻¹]) :=
  fun r₁ r₂ h => by
  rw [numeratorHom_apply, numeratorHom_apply, oreDiv_eq_iff] at h
  rcases h with ⟨u, v, h₁, h₂⟩
  

Proof state:
case intro.intro.intro
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
hS : S ≤ R⁰
r₁ r₂ : R
u : ↥S
v : R
h₁ : r₂ * ↑u = r₁ * v
h₂ : ↑1 * ↑u = ↑1 * v
⊢ r₁ = r₂

Next tactic:
simp only [S.coe_one, one_mul] at h₂
theorem numeratorHom_inj (hS : S ≤ R⁰) : Function.Injective (numeratorHom : R → R[S⁻¹]) :=
  fun r₁ r₂ h => by
  rw [numeratorHom_apply, numeratorHom_apply, oreDiv_eq_iff] at h
  rcases h with ⟨u, v, h₁, h₂⟩
  simp only [S.coe_one, one_mul] at h₂
  

Proof state:
case intro.intro.intro
R : Type u_1
inst✝¹ : Ring R
S : Submonoid R
inst✝ : OreSet S
hS : S ≤ R⁰
r₁ r₂ : R
u : ↥S
v : R
h₁ : r₂ * ↑u = r₁ * v
h₂ : ↑u = v
⊢ r₁ = r₂

Next tactic:
rwa [← h₂, mul_cancel_right_mem_nonZeroDivisors (hS (SetLike.coe_mem u)), eq_comm] at h₁
theorem nontrivial_of_nonZeroDivisors [Nontrivial R] (hS : S ≤ R⁰) : Nontrivial R[S⁻¹] :=
  ⟨⟨0, 1, fun h => by
      

Proof state:
R : Type u_1
inst✝² : Ring R
S : Submonoid R
inst✝¹ : OreSet S
inst✝ : Nontrivial R
hS : S ≤ R⁰
h : 0 = 1
⊢ False

Next tactic:
rw [OreLocalization.one_def, OreLocalization.zero_def] at h
theorem nontrivial_of_nonZeroDivisors [Nontrivial R] (hS : S ≤ R⁰) : Nontrivial R[S⁻¹] :=
  ⟨⟨0, 1, fun h => by
      rw [OreLocalization.one_def, OreLocalization.zero_def] at h
      

Proof state:
R : Type u_1
inst✝² : Ring R
S : Submonoid R
inst✝¹ : OreSet S
inst✝ : Nontrivial R
hS : S ≤ R⁰
h : 0 /ₒ 1 = 1 /ₒ 1
⊢ False

Next tactic:
apply nonZeroDivisors.coe_ne_zero 1 (numeratorHom_inj hS h).symm
/-- The inversion of Ore fractions for a ring without zero divisors, satisying `0⁻¹ = 0` and
`(r /ₒ r')⁻¹ = r' /ₒ r` for `r ≠ 0`. -/
protected def inv : R[R⁰⁻¹] → R[R⁰⁻¹] :=
  liftExpand
    (fun r s =>
      if hr : r = (0 : R) then (0 : R[R⁰⁻¹])
      else s /ₒ ⟨r, fun _ => eq_zero_of_ne_zero_of_mul_right_eq_zero hr⟩)
    (by
      

Proof state:
R : Type u_1
inst✝³ : Ring R
inst✝² : Nontrivial R
inst✝¹ : OreSet R⁰
inst✝ : NoZeroDivisors R
⊢ ∀ (r t : R) (s : ↥R⁰) (ht : ↑s * t ∈ R⁰),
    (fun r s => if hr : r = 0 then 0 else ↑s /ₒ { val := r, property := (_ : ∀ (x : R), x * r = 0 → x = 0) }) r s =
      (fun r s => if hr : r = 0 then 0 else ↑s /ₒ { val := r, property := (_ : ∀ (x : R), x * r = 0 → x = 0) }) (r * t)
        { val := ↑s * t, property := ht }

Next tactic:
intro r t s hst
/-- The inversion of Ore fractions for a ring without zero divisors, satisying `0⁻¹ = 0` and
`(r /ₒ r')⁻¹ = r' /ₒ r` for `r ≠ 0`. -/
protected def inv : R[R⁰⁻¹] → R[R⁰⁻¹] :=
  liftExpand
    (fun r s =>
      if hr : r = (0 : R) then (0 : R[R⁰⁻¹])
      else s /ₒ ⟨r, fun _ => eq_zero_of_ne_zero_of_mul_right_eq_zero hr⟩)
    (by
      intro r t s hst
      

Proof state:
R : Type u_1
inst✝³ : Ring R
inst✝² : Nontrivial R
inst✝¹ : OreSet R⁰
inst✝ : NoZeroDivisors R
r t : R
s : ↥R⁰
hst : ↑s * t ∈ R⁰
⊢ (fun r s => if hr : r = 0 then 0 else ↑s /ₒ { val := r, property := (_ : ∀ (x : R), x * r = 0 → x = 0) }) r s =
    (fun r s => if hr : r = 0 then 0 else ↑s /ₒ { val := r, property := (_ : ∀ (x : R), x * r = 0 → x = 0) }) (r * t)
      { val := ↑s * t, property := hst }

Next tactic:
by_cases hr : r = 0