l3lab/ntp-mathlib huggingface dataset:
protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := by
  -- Porting note: `assoc_rw` was not ported yet
  induction' x using OreLocalization.ind with r₁ s₁
  induction' y using OreLocalization.ind with r₂ s₂
  induction' z using OreLocalization.ind with r₃ s₃
  rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha'
  rcases oreDivMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb'
  rcases oreCondition rb sa with ⟨rc, sc, hc⟩
  rw [oreDiv_mul_char (r₁ * ra) r₃ (s₂ * sa) s₃ rc (sb * sc)
      (by
        simp only [Submonoid.coe_mul]
        

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
ra : R
sa : ↥S
ha : r₂ * ↑sa = ↑s₁ * ra
rb : R
sb : ↥S
hb : r₃ * ↑sb = ↑s₂ * rb
rc : R
sc : ↥S
hc : rb * ↑sc = ↑sa * rc
⊢ r₃ * (↑sb * ↑sc) = ↑s₂ * ↑sa * rc

Next tactic:
rw [← mul_assoc, hb, mul_assoc, hc, ← mul_assoc]
protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := by
  -- Porting note: `assoc_rw` was not ported yet
  induction' x using OreLocalization.ind with r₁ s₁
  induction' y using OreLocalization.ind with r₂ s₂
  induction' z using OreLocalization.ind with r₃ s₃
  rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha'
  rcases oreDivMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb'
  rcases oreCondition rb sa with ⟨rc, sc, hc⟩
  rw [oreDiv_mul_char (r₁ * ra) r₃ (s₂ * sa) s₃ rc (sb * sc)
      (by
        simp only [Submonoid.coe_mul]
        rw [← mul_assoc, hb, mul_assoc, hc, ← mul_assoc])]
  

Proof state:
case c.c.c.mk.mk.intro.mk.mk.intro.mk.mk
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
ra : R
sa : ↥S
ha : r₂ * ↑sa = ↑s₁ * ra
rb : R
sb : ↥S
hb : r₃ * ↑sb = ↑s₂ * rb
rc : R
sc : ↥S
hc : rb * ↑sc = ↑sa * rc
⊢ r₁ * ra * rc /ₒ (s₃ * (sb * sc)) = r₁ /ₒ s₁ * (r₂ * rb /ₒ (s₃ * sb))

Next tactic:
rw [mul_assoc, ← mul_assoc s₃]
protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := by
  -- Porting note: `assoc_rw` was not ported yet
  induction' x using OreLocalization.ind with r₁ s₁
  induction' y using OreLocalization.ind with r₂ s₂
  induction' z using OreLocalization.ind with r₃ s₃
  rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha'
  rcases oreDivMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb'
  rcases oreCondition rb sa with ⟨rc, sc, hc⟩
  rw [oreDiv_mul_char (r₁ * ra) r₃ (s₂ * sa) s₃ rc (sb * sc)
      (by
        simp only [Submonoid.coe_mul]
        rw [← mul_assoc, hb, mul_assoc, hc, ← mul_assoc])]
  rw [mul_assoc, ← mul_assoc s₃]
  

Proof state:
case c.c.c.mk.mk.intro.mk.mk.intro.mk.mk
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
ra : R
sa : ↥S
ha : r₂ * ↑sa = ↑s₁ * ra
rb : R
sb : ↥S
hb : r₃ * ↑sb = ↑s₂ * rb
rc : R
sc : ↥S
hc : rb * ↑sc = ↑sa * rc
⊢ r₁ * (ra * rc) /ₒ (s₃ * sb * sc) = r₁ /ₒ s₁ * (r₂ * rb /ₒ (s₃ * sb))

Next tactic:
symm
protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := by
  -- Porting note: `assoc_rw` was not ported yet
  induction' x using OreLocalization.ind with r₁ s₁
  induction' y using OreLocalization.ind with r₂ s₂
  induction' z using OreLocalization.ind with r₃ s₃
  rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha'
  rcases oreDivMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb'
  rcases oreCondition rb sa with ⟨rc, sc, hc⟩
  rw [oreDiv_mul_char (r₁ * ra) r₃ (s₂ * sa) s₃ rc (sb * sc)
      (by
        simp only [Submonoid.coe_mul]
        rw [← mul_assoc, hb, mul_assoc, hc, ← mul_assoc])]
  rw [mul_assoc, ← mul_assoc s₃]
  symm; 

Proof state:
case c.c.c.mk.mk.intro.mk.mk.intro.mk.mk
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
ra : R
sa : ↥S
ha : r₂ * ↑sa = ↑s₁ * ra
rb : R
sb : ↥S
hb : r₃ * ↑sb = ↑s₂ * rb
rc : R
sc : ↥S
hc : rb * ↑sc = ↑sa * rc
⊢ r₁ /ₒ s₁ * (r₂ * rb /ₒ (s₃ * sb)) = r₁ * (ra * rc) /ₒ (s₃ * sb * sc)

Next tactic:
apply oreDiv_mul_char
protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := by
  -- Porting note: `assoc_rw` was not ported yet
  induction' x using OreLocalization.ind with r₁ s₁
  induction' y using OreLocalization.ind with r₂ s₂
  induction' z using OreLocalization.ind with r₃ s₃
  rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha'
  rcases oreDivMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb'
  rcases oreCondition rb sa with ⟨rc, sc, hc⟩
  rw [oreDiv_mul_char (r₁ * ra) r₃ (s₂ * sa) s₃ rc (sb * sc)
      (by
        simp only [Submonoid.coe_mul]
        rw [← mul_assoc, hb, mul_assoc, hc, ← mul_assoc])]
  rw [mul_assoc, ← mul_assoc s₃]
  symm; apply oreDiv_mul_char
  

Proof state:
case c.c.c.mk.mk.intro.mk.mk.intro.mk.mk.huv
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
r₃ : R
s₃ : ↥S
ra : R
sa : ↥S
ha : r₂ * ↑sa = ↑s₁ * ra
rb : R
sb : ↥S
hb : r₃ * ↑sb = ↑s₂ * rb
rc : R
sc : ↥S
hc : rb * ↑sc = ↑sa * rc
⊢ r₂ * rb * ↑sc = ↑s₁ * (ra * rc)

Next tactic:
rw [mul_assoc, hc, ← mul_assoc (b := ra), ← ha, mul_assoc]
protected theorem mul_inv (s s' : S) : ((s : R) /ₒ s') * ((s' : R) /ₒ s) = 1 := by
  

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
s s' : ↥S
⊢ ↑s /ₒ s' * (↑s' /ₒ s) = 1

Next tactic:
simp [oreDiv_mul_char (s : R) s' s' s 1 1 (by simp)]
protected theorem mul_inv (s s' : S) : ((s : R) /ₒ s') * ((s' : R) /ₒ s) = 1 := by
  simp [oreDiv_mul_char (s : R) s' s' s 1 1 (by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
s s' : ↥S
⊢ ↑s' * ↑1 = ↑s' * 1

Next tactic:
simp
@[simp]
protected theorem mul_one_div {r : R} {s t : S} : (r /ₒ s) * (1 /ₒ t) = r /ₒ (t * s) := by
  

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r : R
s t : ↥S
⊢ r /ₒ s * (1 /ₒ t) = r /ₒ (t * s)

Next tactic:
simp [oreDiv_mul_char r 1 s t 1 s (by simp)]
@[simp]
protected theorem mul_one_div {r : R} {s t : S} : (r /ₒ s) * (1 /ₒ t) = r /ₒ (t * s) := by
  simp [oreDiv_mul_char r 1 s t 1 s (by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r : R
s t : ↥S
⊢ 1 * ↑s = ↑s * 1

Next tactic:
simp
@[simp]
protected theorem mul_cancel {r : R} {s t : S} : (r /ₒ s) * ((s : R) /ₒ t) = r /ₒ t := by
  

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r : R
s t : ↥S
⊢ r /ₒ s * (↑s /ₒ t) = r /ₒ t

Next tactic:
simp [oreDiv_mul_char r s s t 1 1 (by simp)]
@[simp]
protected theorem mul_cancel {r : R} {s t : S} : (r /ₒ s) * ((s : R) /ₒ t) = r /ₒ t := by
  simp [oreDiv_mul_char r s s t 1 1 (by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r : R
s t : ↥S
⊢ ↑s * ↑1 = ↑s * 1

Next tactic:
simp
@[simp]
protected theorem mul_cancel' {r₁ r₂ : R} {s t : S} :
    (r₁ /ₒ s) * ((s * r₂) /ₒ t) = (r₁ * r₂) /ₒ t := by
  

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s t : ↥S
⊢ r₁ /ₒ s * (↑s * r₂ /ₒ t) = r₁ * r₂ /ₒ t

Next tactic:
simp [oreDiv_mul_char r₁ (s * r₂) s t r₂ 1 (by simp)]
@[simp]
protected theorem mul_cancel' {r₁ r₂ : R} {s t : S} :
    (r₁ /ₒ s) * ((s * r₂) /ₒ t) = (r₁ * r₂) /ₒ t := by
  simp [oreDiv_mul_char r₁ (s * r₂) s t r₂ 1 (by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s t : ↥S
⊢ ↑s * r₂ * ↑1 = ↑s * r₂

Next tactic:
simp
@[simp]
theorem div_one_mul {p r : R} {s : S} : (r /ₒ 1) * (p /ₒ s) = (r * p) /ₒ s := by
  --TODO use coercion r ↦ r /ₒ 1
  

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
p r : R
s : ↥S
⊢ r /ₒ 1 * (p /ₒ s) = r * p /ₒ s

Next tactic:
simp [oreDiv_mul_char r p 1 s p 1 (by simp)]
@[simp]
theorem div_one_mul {p r : R} {s : S} : (r /ₒ 1) * (p /ₒ s) = (r * p) /ₒ s := by
  --TODO use coercion r ↦ r /ₒ 1
  simp [oreDiv_mul_char r p 1 s p 1 (by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
S : Submonoid R
inst✝ : OreSet S
p r : R
s : ↥S
⊢ p * ↑1 = ↑1 * p

Next tactic:
simp
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
⊢ (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht }

Next tactic:
simp only []
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
⊢ f r * ↑(fS s)⁻¹ = f (r * t) * ↑(fS { val := ↑s * t, property := ht })⁻¹

Next tactic:
have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
⊢ ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t

Next tactic:
simp only [← hf, MonoidHom.map_mul]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
this : ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t
⊢ f r * ↑(fS s)⁻¹ = f (r * t) * ↑(fS { val := ↑s * t, property := ht })⁻¹

Next tactic:
conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
this : ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t
| f (r * t) * ↑(fS { val := ↑s * t, property := ht })⁻¹

Next tactic:
rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
this : ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t
| f (r * t) * ↑(fS { val := ↑s * t, property := ht })⁻¹

Next tactic:
rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
this : ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t
| f r * ↑((fS s)⁻¹ * fS s) * f t * ↑(fS { val := ↑s * t, property := ht })⁻¹

Next tactic:
rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x : OreLocalization R S
r t : R
s : ↥S
ht : ↑s * t ∈ S
this : ↑(fS { val := ↑s * t, property := ht }) = ↑(fS s) * f t
⊢ f r * ↑(fS s)⁻¹ =
    f r * ↑(fS s)⁻¹ * (↑(fS { val := ↑s * t, property := ht }) * ↑(fS { val := ↑s * t, property := ht })⁻¹)

Next tactic:
simp only [mul_one, Units.mul_inv]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by 

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
⊢ (fun x =>
        liftExpand (fun r s => f r * ↑(fS s)⁻¹)
          (_ :
            ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
              (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
          x)
      1 =
    1

Next tactic:
simp only []
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by simp only []; 

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
⊢ liftExpand (fun r s => f r * ↑(fS s)⁻¹)
      (_ :
        ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
          (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
      1 =
    1

Next tactic:
rw [OreLocalization.one_def, liftExpand_of]
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by simp only []; rw [OreLocalization.one_def, liftExpand_of]; 

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
⊢ f 1 * ↑(fS 1)⁻¹ = 1

Next tactic:
simp
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by simp only []; rw [OreLocalization.one_def, liftExpand_of]; simp
  map_mul' x y := by
    simp only []
    

Proof state:
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
x y : OreLocalization R S
⊢ liftExpand (fun r s => f r * ↑(fS s)⁻¹)
      (_ :
        ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
          (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
      (x * y) =
    liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        x *
      liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        y

Next tactic:
induction' x using OreLocalization.ind with r₁ s₁
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by simp only []; rw [OreLocalization.one_def, liftExpand_of]; simp
  map_mul' x y := by
    simp only []
    induction' x using OreLocalization.ind with r₁ s₁
    

Proof state:
case c
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
y : OreLocalization R S
r₁ : R
s₁ : ↥S
⊢ liftExpand (fun r s => f r * ↑(fS s)⁻¹)
      (_ :
        ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
          (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
      (r₁ /ₒ s₁ * y) =
    liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        (r₁ /ₒ s₁) *
      liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        y

Next tactic:
induction' y using OreLocalization.ind with r₂ s₂
/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`,
to a morphism `R[S⁻¹] →* T`. -/
def universalMulHom : R[S⁻¹] →* T
    where
  -- Porting note: `simp only []` required for beta reductions
  toFun x :=
    x.liftExpand (fun r s => f r * ((fS s)⁻¹ : Units T)) fun r t s ht => by
      simp only []
      have : (fS ⟨s * t, ht⟩ : T) = fS s * f t := by
        simp only [← hf, MonoidHom.map_mul]
      conv_rhs =>
        rw [MonoidHom.map_mul, ← mul_one (f r), ← Units.val_one, ← mul_left_inv (fS s)]
        rw [Units.val_mul, ← mul_assoc, mul_assoc _ (fS s : T), ← this, mul_assoc]
      simp only [mul_one, Units.mul_inv]
  map_one' := by simp only []; rw [OreLocalization.one_def, liftExpand_of]; simp
  map_mul' x y := by
    simp only []
    induction' x using OreLocalization.ind with r₁ s₁
    induction' y using OreLocalization.ind with r₂ s₂
    

Proof state:
case c.c
R : Type u_1
inst✝² : Monoid R
S : Submonoid R
inst✝¹ : OreSet S
T : Type u_2
inst✝ : Monoid T
f : R →* T
fS : ↥S →* Tˣ
hf : ∀ (s : ↥S), f ↑s = ↑(fS s)
r₁ : R
s₁ : ↥S
r₂ : R
s₂ : ↥S
⊢ liftExpand (fun r s => f r * ↑(fS s)⁻¹)
      (_ :
        ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
          (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
      (r₁ /ₒ s₁ * (r₂ /ₒ s₂)) =
    liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        (r₁ /ₒ s₁) *
      liftExpand (fun r s => f r * ↑(fS s)⁻¹)
        (_ :
          ∀ (r t : R) (s : ↥S) (ht : ↑s * t ∈ S),
            (fun r s => f r * ↑(fS s)⁻¹) r s = (fun r s => f r * ↑(fS s)⁻¹) (r * t) { val := ↑s * t, property := ht })
        (r₂ /ₒ s₂)

Next tactic:
rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩