l3lab/ntp-mathlib huggingface dataset:
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    

Proof state:
case mk.mk.intro.intro.intro.mk.mk.mk.mk
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd)
⊢ ∃ u v, (r₁' * ↑sc + r₂ * rc) * rd * ↑u = (r₁' * ↑sc + r₂ * rc) * v ∧ ↑(s₁ * (sb * sd)) * ↑u = ↑(s₁' * sc) * v

Next tactic:
use 1
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    use 1
    

Proof state:
case h
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd)
⊢ ∃ v, (r₁' * ↑sc + r₂ * rc) * rd * ↑1 = (r₁' * ↑sc + r₂ * rc) * v ∧ ↑(s₁ * (sb * sd)) * ↑1 = ↑(s₁' * sc) * v

Next tactic:
use rd
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    use 1
    use rd
    

Proof state:
case h
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd)
⊢ (r₁' * ↑sc + r₂ * rc) * rd * ↑1 = (r₁' * ↑sc + r₂ * rc) * rd ∧ ↑(s₁ * (sb * sd)) * ↑1 = ↑(s₁' * sc) * rd

Next tactic:
constructor
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    use 1
    use rd
    constructor
    · 

Proof state:
case h.left
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd)
⊢ (r₁' * ↑sc + r₂ * rc) * rd * ↑1 = (r₁' * ↑sc + r₂ * rc) * rd

Next tactic:
simp
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    use 1
    use rd
    constructor
    · simp
    · 

Proof state:
case h.right
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd)
⊢ ↑(s₁ * (sb * sd)) * ↑1 = ↑(s₁' * sc) * rd

Next tactic:
simp only [mul_one, Submonoid.coe_one, Submonoid.coe_mul] at this ⊢
private def add' (r₂ : R) (s₂ : S) : R[S⁻¹] → R[S⁻¹] :=
  (--plus tilde
      Quotient.lift
      fun r₁s₁ : R × S => add'' r₁s₁.1 r₁s₁.2 r₂ s₂) <| by
    -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
    rintro ⟨r₁', s₁'⟩ ⟨r₁, s₁⟩ ⟨sb, rb, hb, hb'⟩
    -- s*, r*
    rcases oreCondition (s₁' : R) s₂ with ⟨rc, sc, hc⟩
    --s~~, r~~
    rcases oreCondition rb sc with ⟨rd, sd, hd⟩
    -- s#, r#
    dsimp at *
    rw [add''_char _ _ _ _ rc sc hc]
    have : ↑s₁ * ↑(sb * sd) = ↑s₂ * (rc * rd) := by
      simp only [Submonoid.coe_mul]
      rw [← mul_assoc, hb', mul_assoc, hd, ← mul_assoc, hc, mul_assoc]
    rw [add''_char _ _ _ _ (rc * rd : R) (sb * sd : S) this]
    simp only [Submonoid.coe_mul]
    rw [← mul_assoc (a := r₁) (b := (sb : R)), hb, mul_assoc (a := r₁') (b := (rb : R)), hd,
      ← mul_assoc, ← mul_assoc, ← add_mul, oreDiv_eq_iff]
    use 1
    use rd
    constructor
    · simp
    · simp only [mul_one, Submonoid.coe_one, Submonoid.coe_mul] at this ⊢
      

Proof state:
case h.right
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₂ : R
s₂ : ↥S
r₁' : R
s₁' : ↥S
r₁ : R
s₁ : ↥S
sb : ↥S
rb : R
hb : r₁ * ↑sb = r₁' * rb
hb' : ↑s₁ * ↑sb = ↑s₁' * rb
rc : R
sc : ↥S
hc : ↑s₁' * ↑sc = ↑s₂ * rc
rd : R
sd : ↥S
hd : rb * ↑sd = ↑sc * rd
this : ↑s₁ * (↑sb * ↑sd) = ↑s₂ * (rc * rd)
⊢ ↑s₁ * (↑sb * ↑sd) = ↑s₁' * ↑sc * rd

Next tactic:
rw [hc, this, mul_assoc]
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
⊢ OreLocalization.add' r₁ s₁ (r₂ /ₒ s₂) = OreLocalization.add' r₂ s₂ (r₁ /ₒ s₁)

Next tactic:
simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
⊢ ⟦(r₂ * ↑(oreDenom (↑s₂) s₁) + r₁ * oreNum (↑s₂) s₁, s₂ * oreDenom (↑s₂) s₁)⟧ =
    ⟦(r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)⟧

Next tactic:
rw [Quotient.eq]
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
⊢ (r₂ * ↑(oreDenom (↑s₂) s₁) + r₁ * oreNum (↑s₂) s₁, s₂ * oreDenom (↑s₂) s₁) ≈
    (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
have hb := ore_eq (↑s₂) s₁
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
hb : ↑s₂ * ↑(oreDenom (↑s₂) s₁) = ↑s₁ * oreNum (↑s₂) s₁
⊢ (r₂ * ↑(oreDenom (↑s₂) s₁) + r₁ * oreNum (↑s₂) s₁, s₂ * oreDenom (↑s₂) s₁) ≈
    (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
set rb := oreNum (↑s₂) s₁
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
hb : ↑s₂ * ↑(oreDenom (↑s₂) s₁) = ↑s₁ * rb
⊢ (r₂ * ↑(oreDenom (↑s₂) s₁) + r₁ * rb, s₂ * oreDenom (↑s₂) s₁) ≈
    (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
set sb := oreDenom (↑s₂) s₁
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
have ha := ore_eq (↑s₁) s₂
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ha : ↑s₁ * ↑(oreDenom (↑s₁) s₂) = ↑s₂ * oreNum (↑s₁) s₂
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * oreNum (↑s₁) s₂, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
set ra := oreNum (↑s₁) s₂
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
ha : ↑s₁ * ↑(oreDenom (↑s₁) s₂) = ↑s₂ * ra
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑(oreDenom (↑s₁) s₂) + r₂ * ra, s₁ * oreDenom (↑s₁) s₂)

Next tactic:
set sa := oreDenom (↑s₁) s₂
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑sa + r₂ * ra, s₁ * sa)

Next tactic:
rcases oreCondition ra sb with ⟨rc, sc, hc⟩
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  

Proof state:
case mk.mk
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
rc : R
sc : ↥S
hc : ra * ↑sc = ↑sb * rc
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑sa + r₂ * ra, s₁ * sa)

Next tactic:
have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    

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

Next tactic:
rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
  

Proof state:
case mk.mk
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
rc : R
sc : ↥S
hc : ra * ↑sc = ↑sb * rc
this : ↑s₁ * (rb * rc) = ↑s₁ * (↑sa * ↑sc)
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑sa + r₂ * ra, s₁ * sa)

Next tactic:
rcases ore_left_cancel _ _ s₁ this with ⟨sd, hd⟩
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
  rcases ore_left_cancel _ _ s₁ this with ⟨sd, hd⟩
  -- s+
  

Proof state:
case mk.mk.intro
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
rc : R
sc : ↥S
hc : ra * ↑sc = ↑sb * rc
this : ↑s₁ * (rb * rc) = ↑s₁ * (↑sa * ↑sc)
sd : ↥S
hd : rb * rc * ↑sd = ↑sa * ↑sc * ↑sd
⊢ (r₂ * ↑sb + r₁ * rb, s₂ * sb) ≈ (r₁ * ↑sa + r₂ * ra, s₁ * sa)

Next tactic:
use sc * sd
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
  rcases ore_left_cancel _ _ s₁ this with ⟨sd, hd⟩
  -- s+
  use sc * sd
  

Proof state:
case h
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
rc : R
sc : ↥S
hc : ra * ↑sc = ↑sb * rc
this : ↑s₁ * (rb * rc) = ↑s₁ * (↑sa * ↑sc)
sd : ↥S
hd : rb * rc * ↑sd = ↑sa * ↑sc * ↑sd
⊢ ∃ v,
    (r₁ * ↑sa + r₂ * ra, s₁ * sa).1 * ↑(sc * sd) = (r₂ * ↑sb + r₁ * rb, s₂ * sb).1 * v ∧
      ↑(r₁ * ↑sa + r₂ * ra, s₁ * sa).2 * ↑(sc * sd) = ↑(r₂ * ↑sb + r₁ * rb, s₂ * sb).2 * v

Next tactic:
use rc * sd
private theorem add'_comm (r₁ r₂ : R) (s₁ s₂ : S) :
    add' r₁ s₁ (r₂ /ₒ s₂) = add' r₂ s₂ (r₁ /ₒ s₁) := by
  -- Porting note: `assoc_rw` & `noncomm_ring` were not ported yet
  -- Porting note: `Quotient.mk'` required
  simp only [add', oreDiv, add'', Quotient.mk', Quotient.lift_mk]
  -- Porting note: `Quotient.eq` should be used in `rw` instead of `simp`
  rw [Quotient.eq]
  have hb := ore_eq (↑s₂) s₁
  -- Porting note: `set ... with h; rw [← h]; clear h`s aren't required anymore
  set rb := oreNum (↑s₂) s₁
  set sb := oreDenom (↑s₂) s₁
  have ha := ore_eq (↑s₁) s₂
  set ra := oreNum (↑s₁) s₂
  set sa := oreDenom (↑s₁) s₂
  rcases oreCondition ra sb with ⟨rc, sc, hc⟩
  -- r#, s#
  have : (s₁ : R) * (rb * rc) = s₁ * (sa * sc) := by
    rw [← mul_assoc, ← hb, mul_assoc, ← hc, ← mul_assoc, ← ha, mul_assoc]
  rcases ore_left_cancel _ _ s₁ this with ⟨sd, hd⟩
  -- s+
  use sc * sd
  use rc * sd
  

Proof state:
case h
R : Type u_1
inst✝¹ : Semiring R
S : Submonoid R
inst✝ : OreSet S
r₁ r₂ : R
s₁ s₂ : ↥S
rb : R := oreNum (↑s₂) s₁
sb : ↥S := oreDenom (↑s₂) s₁
hb : ↑s₂ * ↑sb = ↑s₁ * rb
ra : R := oreNum (↑s₁) s₂
sa : ↥S := oreDenom (↑s₁) s₂
ha : ↑s₁ * ↑sa = ↑s₂ * ra
rc : R
sc : ↥S
hc : ra * ↑sc = ↑sb * rc
this : ↑s₁ * (rb * rc) = ↑s₁ * (↑sa * ↑sc)
sd : ↥S
hd : rb * rc * ↑sd = ↑sa * ↑sc * ↑sd
⊢ (r₁ * ↑sa + r₂ * ra, s₁ * sa).1 * ↑(sc * sd) = (r₂ * ↑sb + r₁ * rb, s₂ * sb).1 * (rc * ↑sd) ∧
    ↑(r₁ * ↑sa + r₂ * ra, s₁ * sa).2 * ↑(sc * sd) = ↑(r₂ * ↑sb + r₁ * rb, s₂ * sb).2 * (rc * ↑sd)

Next tactic:
dsimp