l3lab/ntp-mathlib huggingface dataset:
/-- `TensorProduct.assoc` corresponds to a permutation of the identity matrix. -/
theorem TensorProduct.toMatrix_assoc :
    toMatrix ((bM.tensorProduct bN).tensorProduct bP) (bM.tensorProduct (bN.tensorProduct bP))
        (TensorProduct.assoc R M N P) =
      (1 : Matrix (ι × κ × τ) (ι × κ × τ) R).submatrix _root_.id (Equiv.prodAssoc _ _ _) := by
  ext ⟨i, j, k⟩ ⟨⟨i', j'⟩, k'⟩
  simp_rw [toMatrix_apply, Basis.tensorProduct_apply, LinearEquiv.coe_coe,
    TensorProduct.assoc_tmul, Basis.tensorProduct_repr_tmul_apply, Matrix.submatrix_apply,
    Equiv.prodAssoc_apply, id.def, Basis.repr_self_apply, Matrix.one_apply, Prod.ext_iff, ite_and,
    @eq_comm _ i', @eq_comm _ j', @eq_comm _ k']
  split_ifs <;> 

Proof state:
case pos
R : Type u_1
M : Type u_2
N : Type u_3
P : Type u_4
M' : Type u_5
N' : Type u_6
ι : Type u_7
κ : Type u_8
τ : Type u_9
ι' : Type u_10
κ' : Type u_11
inst✝¹⁸ : DecidableEq ι
inst✝¹⁷ : DecidableEq κ
inst✝¹⁶ : DecidableEq τ
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : Fintype κ
inst✝¹³ : Fintype τ
inst✝¹² : Fintype ι'
inst✝¹¹ : Fintype κ'
inst✝¹⁰ : CommRing R
inst✝⁹ : AddCommGroup M
inst✝⁸ : AddCommGroup N
inst✝⁷ : AddCommGroup P
inst✝⁶ : AddCommGroup M'
inst✝⁵ : AddCommGroup N'
inst✝⁴ : Module R M
inst✝³ : Module R N
inst✝² : Module R P
inst✝¹ : Module R M'
inst✝ : Module R N'
bM : Basis ι R M
bN : Basis κ R N
bP : Basis τ R P
bM' : Basis ι' R M'
bN' : Basis κ' R N'
i : ι
j : κ
k k' : τ
i' : ι
j' : κ
h✝² : ¬i = i'
h✝¹ : ¬j = j'
h✝ : k = k'
⊢ 0 * (0 * 1) = 0

Next tactic:
simp
/-- `TensorProduct.assoc` corresponds to a permutation of the identity matrix. -/
theorem TensorProduct.toMatrix_assoc :
    toMatrix ((bM.tensorProduct bN).tensorProduct bP) (bM.tensorProduct (bN.tensorProduct bP))
        (TensorProduct.assoc R M N P) =
      (1 : Matrix (ι × κ × τ) (ι × κ × τ) R).submatrix _root_.id (Equiv.prodAssoc _ _ _) := by
  ext ⟨i, j, k⟩ ⟨⟨i', j'⟩, k'⟩
  simp_rw [toMatrix_apply, Basis.tensorProduct_apply, LinearEquiv.coe_coe,
    TensorProduct.assoc_tmul, Basis.tensorProduct_repr_tmul_apply, Matrix.submatrix_apply,
    Equiv.prodAssoc_apply, id.def, Basis.repr_self_apply, Matrix.one_apply, Prod.ext_iff, ite_and,
    @eq_comm _ i', @eq_comm _ j', @eq_comm _ k']
  split_ifs <;> 

Proof state:
case neg
R : Type u_1
M : Type u_2
N : Type u_3
P : Type u_4
M' : Type u_5
N' : Type u_6
ι : Type u_7
κ : Type u_8
τ : Type u_9
ι' : Type u_10
κ' : Type u_11
inst✝¹⁸ : DecidableEq ι
inst✝¹⁷ : DecidableEq κ
inst✝¹⁶ : DecidableEq τ
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : Fintype κ
inst✝¹³ : Fintype τ
inst✝¹² : Fintype ι'
inst✝¹¹ : Fintype κ'
inst✝¹⁰ : CommRing R
inst✝⁹ : AddCommGroup M
inst✝⁸ : AddCommGroup N
inst✝⁷ : AddCommGroup P
inst✝⁶ : AddCommGroup M'
inst✝⁵ : AddCommGroup N'
inst✝⁴ : Module R M
inst✝³ : Module R N
inst✝² : Module R P
inst✝¹ : Module R M'
inst✝ : Module R N'
bM : Basis ι R M
bN : Basis κ R N
bP : Basis τ R P
bM' : Basis ι' R M'
bN' : Basis κ' R N'
i : ι
j : κ
k k' : τ
i' : ι
j' : κ
h✝² : ¬i = i'
h✝¹ : ¬j = j'
h✝ : ¬k = k'
⊢ 0 * (0 * 0) = 0

Next tactic:
simp
theorem toFractionRing_injective : Function.Injective (toFractionRing : _ → FractionRing K[X])
  -- porting note: the `xy` input was `rfl` and then there was no need for the `subst`
  | ⟨x⟩, ⟨y⟩, xy => by 

Proof state:
K : Type u
inst✝ : CommRing K
x y : FractionRing K[X]
xy : { toFractionRing := x }.toFractionRing = { toFractionRing := y }.toFractionRing
⊢ { toFractionRing := x } = { toFractionRing := y }

Next tactic:
subst xy
theorem toFractionRing_injective : Function.Injective (toFractionRing : _ → FractionRing K[X])
  -- porting note: the `xy` input was `rfl` and then there was no need for the `subst`
  | ⟨x⟩, ⟨y⟩, xy => by subst xy; 

Proof state:
K : Type u
inst✝ : CommRing K
x : FractionRing K[X]
⊢ { toFractionRing := x } = { toFractionRing := { toFractionRing := x }.toFractionRing }

Next tactic:
rfl
/-- Non-dependent recursion principle for `RatFunc K`:
To construct a term of `P : Sort*` out of `x : RatFunc K`,
it suffices to provide a constructor `f : Π (p q : K[X]), P`
and a proof that `f p q = f p' q'` for all `p q p' q'` such that `q' * p = q * p'` where
both `q` and `q'` are not zero divisors, stated as `q ∉ K[X]⁰`, `q' ∉ K[X]⁰`.

If considering `K` as an integral domain, this is the same as saying that
we construct a value of `P` for such elements of `RatFunc K` by setting
`liftOn (p / q) f _ = f p q`.

When `[IsDomain K]`, one can use `RatFunc.liftOn'`, which has the stronger requirement
of `∀ {p q a : K[X]} (hq : q ≠ 0) (ha : a ≠ 0), f (a * p) (a * q) = f p q)`.
-/
protected irreducible_def liftOn {P : Sort v} (x : RatFunc K) (f : ∀ _p _q : K[X], P)
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q') :
    P := by
  

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
x : RatFunc K
f : K[X] → K[X] → P
H : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q'
⊢ P

Next tactic:
refine Localization.liftOn (toFractionRing x) (fun p q => f p q) ?_
/-- Non-dependent recursion principle for `RatFunc K`:
To construct a term of `P : Sort*` out of `x : RatFunc K`,
it suffices to provide a constructor `f : Π (p q : K[X]), P`
and a proof that `f p q = f p' q'` for all `p q p' q'` such that `q' * p = q * p'` where
both `q` and `q'` are not zero divisors, stated as `q ∉ K[X]⁰`, `q' ∉ K[X]⁰`.

If considering `K` as an integral domain, this is the same as saying that
we construct a value of `P` for such elements of `RatFunc K` by setting
`liftOn (p / q) f _ = f p q`.

When `[IsDomain K]`, one can use `RatFunc.liftOn'`, which has the stronger requirement
of `∀ {p q a : K[X]} (hq : q ≠ 0) (ha : a ≠ 0), f (a * p) (a * q) = f p q)`.
-/
protected irreducible_def liftOn {P : Sort v} (x : RatFunc K) (f : ∀ _p _q : K[X], P)
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q') :
    P := by
  refine Localization.liftOn (toFractionRing x) (fun p q => f p q) ?_
  

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
x : RatFunc K
f : K[X] → K[X] → P
H : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q'
⊢ ∀ {a c : K[X]} {b d : ↥K[X]⁰},
    (Localization.r K[X]⁰) (a, b) (c, d) → (fun p q => f p ↑q) a b = (fun p q => f p ↑q) c d

Next tactic:
intros p p' q q' h
/-- Non-dependent recursion principle for `RatFunc K`:
To construct a term of `P : Sort*` out of `x : RatFunc K`,
it suffices to provide a constructor `f : Π (p q : K[X]), P`
and a proof that `f p q = f p' q'` for all `p q p' q'` such that `q' * p = q * p'` where
both `q` and `q'` are not zero divisors, stated as `q ∉ K[X]⁰`, `q' ∉ K[X]⁰`.

If considering `K` as an integral domain, this is the same as saying that
we construct a value of `P` for such elements of `RatFunc K` by setting
`liftOn (p / q) f _ = f p q`.

When `[IsDomain K]`, one can use `RatFunc.liftOn'`, which has the stronger requirement
of `∀ {p q a : K[X]} (hq : q ≠ 0) (ha : a ≠ 0), f (a * p) (a * q) = f p q)`.
-/
protected irreducible_def liftOn {P : Sort v} (x : RatFunc K) (f : ∀ _p _q : K[X], P)
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q') :
    P := by
  refine Localization.liftOn (toFractionRing x) (fun p q => f p q) ?_
  intros p p' q q' h
  

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
x : RatFunc K
f : K[X] → K[X] → P
H : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q'
p p' : K[X]
q q' : ↥K[X]⁰
h : (Localization.r K[X]⁰) (p, q) (p', q')
⊢ (fun p q => f p ↑q) p q = (fun p q => f p ↑q) p' q'

Next tactic:
exact H q.2 q'.2 (let ⟨⟨c, hc⟩, mul_eq⟩ := Localization.r_iff_exists.mp h
    mul_cancel_left_coe_nonZeroDivisors.mp mul_eq)
theorem liftOn_ofFractionRing_mk {P : Sort v} (n : K[X]) (d : K[X]⁰) (f : ∀ _p _q : K[X], P)
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q') :
    RatFunc.liftOn (ofFractionRing (Localization.mk n d)) f @H = f n d := by
  

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
n : K[X]
d : ↥K[X]⁰
f : K[X] → K[X] → P
H : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q'
⊢ RatFunc.liftOn { toFractionRing := Localization.mk n d } f H = f n ↑d

Next tactic:
rw [RatFunc.liftOn]
theorem liftOn_ofFractionRing_mk {P : Sort v} (n : K[X]) (d : K[X]⁰) (f : ∀ _p _q : K[X], P)
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q') :
    RatFunc.liftOn (ofFractionRing (Localization.mk n d)) f @H = f n d := by
  rw [RatFunc.liftOn]
  

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
n : K[X]
d : ↥K[X]⁰
f : K[X] → K[X] → P
H : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q'
⊢ Localization.liftOn { toFractionRing := Localization.mk n d }.toFractionRing (fun p q => f p ↑q)
      (_ : ∀ {p p' : K[X]} {q q' : ↥K[X]⁰}, (Localization.r K[X]⁰) (p, q) (p', q') → f p ↑q = f p' ↑q') =
    f n ↑d

Next tactic:
exact Localization.liftOn_mk _ _ _ _
theorem liftOn_condition_of_liftOn'_condition {P : Sort v} {f : ∀ _p _q : K[X], P}
    (H : ∀ {p q a} (hq : q ≠ 0) (_ha : a ≠ 0), f (a * p) (a * q) = f p q) ⦃p q p' q' : K[X]⦄
    (hq : q ≠ 0) (hq' : q' ≠ 0) (h : q' * p = q * p') : f p q = f p' q' :=
  calc
    f p q = f (q' * p) (q' * q) := (H hq hq').symm
    _ = f (q * p') (q * q') := by 

Proof state:
K : Type u
inst✝ : CommRing K
P : Sort v
f : K[X] → K[X] → P
H : ∀ {p q a : K[X]}, q ≠ 0 → a ≠ 0 → f (a * p) (a * q) = f p q
p q p' q' : K[X]
hq : q ≠ 0
hq' : q' ≠ 0
h : q' * p = q * p'
⊢ f (q' * p) (q' * q) = f (q * p') (q * q')

Next tactic:
rw [h, mul_comm q']
theorem mk_eq_div' (p q : K[X]) :
    RatFunc.mk p q = ofFractionRing (algebraMap _ _ p / algebraMap _ _ q) := by 

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p q : K[X]
⊢ RatFunc.mk p q =
    { toFractionRing := (algebraMap K[X] (FractionRing K[X])) p / (algebraMap K[X] (FractionRing K[X])) q }

Next tactic:
rw [RatFunc.mk]
theorem mk_zero (p : K[X]) : RatFunc.mk p 0 = ofFractionRing (0 : FractionRing K[X]) := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : K[X]
⊢ RatFunc.mk p 0 = { toFractionRing := 0 }

Next tactic:
rw [mk_eq_div', RingHom.map_zero, div_zero]
theorem mk_coe_def (p : K[X]) (q : K[X]⁰) :
    -- porting note: filled in `(FractionRing K[X])` that was an underscore.
    RatFunc.mk p q = ofFractionRing (IsLocalization.mk' (FractionRing K[X]) p q) := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : K[X]
q : ↥K[X]⁰
⊢ RatFunc.mk p ↑q = { toFractionRing := IsLocalization.mk' (FractionRing K[X]) p q }

Next tactic:
simp only [mk_eq_div', ← Localization.mk_eq_mk', FractionRing.mk_eq_div]
theorem mk_def_of_mem (p : K[X]) {q} (hq : q ∈ K[X]⁰) :
    RatFunc.mk p q = ofFractionRing (IsLocalization.mk' (FractionRing K[X]) p ⟨q, hq⟩) := by
  -- porting note: there was an `[anonymous]` in the simp set
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p q : K[X]
hq : q ∈ K[X]⁰
⊢ RatFunc.mk p q = { toFractionRing := IsLocalization.mk' (FractionRing K[X]) p { val := q, property := hq } }

Next tactic:
simp only [← mk_coe_def]
theorem mk_eq_localization_mk (p : K[X]) {q : K[X]} (hq : q ≠ 0) :
    RatFunc.mk p q =
      ofFractionRing (Localization.mk p ⟨q, mem_nonZeroDivisors_iff_ne_zero.mpr hq⟩) := by
  -- porting note: the original proof, did not need to pass `hq`
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p q : K[X]
hq : q ≠ 0
⊢ RatFunc.mk p q = { toFractionRing := Localization.mk p { val := q, property := (_ : q ∈ K[X]⁰) } }

Next tactic:
rw [mk_def_of_ne _ hq, Localization.mk_eq_mk']
theorem mk_one' (p : K[X]) :
    RatFunc.mk p 1 = ofFractionRing (algebraMap K[X] (FractionRing K[X]) p) := by
  -- Porting note: had to hint `M := K[X]⁰` below
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : K[X]
⊢ RatFunc.mk p 1 = { toFractionRing := (algebraMap K[X] (FractionRing K[X])) p }

Next tactic:
rw [← IsLocalization.mk'_one (M := K[X]⁰) (FractionRing K[X]) p, ← mk_coe_def, Submonoid.coe_one]
theorem mk_eq_mk {p q p' q' : K[X]} (hq : q ≠ 0) (hq' : q' ≠ 0) :
    RatFunc.mk p q = RatFunc.mk p' q' ↔ p * q' = p' * q := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p q p' q' : K[X]
hq : q ≠ 0
hq' : q' ≠ 0
⊢ RatFunc.mk p q = RatFunc.mk p' q' ↔ p * q' = p' * q

Next tactic:
rw [mk_def_of_ne _ hq, mk_def_of_ne _ hq', ofFractionRing_injective.eq_iff,
    IsLocalization.mk'_eq_iff_eq', -- porting note: removed `[anonymous], [anonymous]`
    (IsFractionRing.injective K[X] (FractionRing K[X])).eq_iff]
theorem liftOn_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q')
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' :=
      fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) :
    (RatFunc.mk p q).liftOn f @H = f p q := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p q : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H' : ∀ {p q p' q' : K[X]}, q ≠ 0 → q' ≠ 0 → q' * p = q * p' → f p q = f p' q'
H :
  optParam (∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
    (_ : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
⊢ RatFunc.liftOn (RatFunc.mk p q) f H = f p q

Next tactic:
by_cases hq : q = 0
theorem liftOn_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q')
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' :=
      fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) :
    (RatFunc.mk p q).liftOn f @H = f p q := by
  by_cases hq : q = 0
  · 

Proof state:
case pos
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p q : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H' : ∀ {p q p' q' : K[X]}, q ≠ 0 → q' ≠ 0 → q' * p = q * p' → f p q = f p' q'
H :
  optParam (∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
    (_ : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
hq : q = 0
⊢ RatFunc.liftOn (RatFunc.mk p q) f H = f p q

Next tactic:
subst hq
theorem liftOn_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q')
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' :=
      fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) :
    (RatFunc.mk p q).liftOn f @H = f p q := by
  by_cases hq : q = 0
  · subst hq
    

Proof state:
case pos
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H' : ∀ {p q p' q' : K[X]}, q ≠ 0 → q' ≠ 0 → q' * p = q * p' → f p q = f p' q'
H :
  optParam (∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
    (_ : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
⊢ RatFunc.liftOn (RatFunc.mk p 0) f H = f p 0

Next tactic:
simp only [mk_zero, f0, ← Localization.mk_zero 1, Localization.liftOn_mk,
      liftOn_ofFractionRing_mk, Submonoid.coe_one]
theorem liftOn_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q')
    (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' :=
      fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) :
    (RatFunc.mk p q).liftOn f @H = f p q := by
  by_cases hq : q = 0
  · subst hq
    simp only [mk_zero, f0, ← Localization.mk_zero 1, Localization.liftOn_mk,
      liftOn_ofFractionRing_mk, Submonoid.coe_one]
  · 

Proof state:
case neg
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p q : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H' : ∀ {p q p' q' : K[X]}, q ≠ 0 → q' ≠ 0 → q' * p = q * p' → f p q = f p' q'
H :
  optParam (∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
    (_ : ∀ {p q p' q' : K[X]}, q ∈ K[X]⁰ → q' ∈ K[X]⁰ → q' * p = q * p' → f p q = f p' q')
hq : ¬q = 0
⊢ RatFunc.liftOn (RatFunc.mk p q) f H = f p q

Next tactic:
simp only [mk_eq_localization_mk _ hq, Localization.liftOn_mk, liftOn_ofFractionRing_mk]
theorem liftOn'_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H : ∀ {p q a} (_hq : q ≠ 0) (_ha : a ≠ 0), f (a * p) (a * q) = f p q) :
    (RatFunc.mk p q).liftOn' f @H = f p q := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p q : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H : ∀ {p q a : K[X]}, q ≠ 0 → a ≠ 0 → f (a * p) (a * q) = f p q
⊢ RatFunc.liftOn' (RatFunc.mk p q) f H = f p q

Next tactic:
rw [RatFunc.liftOn', RatFunc.liftOn_mk _ _ _ f0]
theorem liftOn'_mk {P : Sort v} (p q : K[X]) (f : ∀ _p _q : K[X], P) (f0 : ∀ p, f p 0 = f 0 1)
    (H : ∀ {p q a} (_hq : q ≠ 0) (_ha : a ≠ 0), f (a * p) (a * q) = f p q) :
    (RatFunc.mk p q).liftOn' f @H = f p q := by
  rw [RatFunc.liftOn', RatFunc.liftOn_mk _ _ _ f0]
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : Sort v
p q : K[X]
f : K[X] → K[X] → P
f0 : ∀ (p : K[X]), f p 0 = f 0 1
H : ∀ {p q a : K[X]}, q ≠ 0 → a ≠ 0 → f (a * p) (a * q) = f p q
⊢ ∀ {p q p' q' : K[X]}, q ≠ 0 → q' ≠ 0 → q' * p = q * p' → f p q = f p' q'

Next tactic:
apply liftOn_condition_of_liftOn'_condition H
/-- Induction principle for `RatFunc K`: if `f p q : P (RatFunc.mk p q)` for all `p q`,
then `P` holds on all elements of `RatFunc K`.

See also `induction_on`, which is a recursion principle defined in terms of `algebraMap`.
-/
@[elab_as_elim]
protected theorem induction_on' {P : RatFunc K → Prop} :
    ∀ (x : RatFunc K) (_pq : ∀ (p q : K[X]) (_ : q ≠ 0), P (RatFunc.mk p q)), P x
  | ⟨x⟩, f =>
    Localization.induction_on x fun ⟨p, q⟩ => by
      

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
P : RatFunc K → Prop
x : FractionRing K[X]
f : ∀ (p q : K[X]), q ≠ 0 → P (RatFunc.mk p q)
x✝ : K[X] × ↥K[X]⁰
p : K[X]
q : ↥K[X]⁰
⊢ P { toFractionRing := Localization.mk (p, q).1 (p, q).2 }

Next tactic:
simpa only [mk_coe_def, Localization.mk_eq_mk'] using
        f p q (mem_nonZeroDivisors_iff_ne_zero.mp q.2)
theorem ofFractionRing_zero : (ofFractionRing 0 : RatFunc K) = 0 := by
  

Proof state:
K : Type u
inst✝ : CommRing K
⊢ { toFractionRing := 0 } = 0

Next tactic:
simp only [Zero.zero, OfNat.ofNat, RatFunc.zero]
theorem ofFractionRing_add (p q : FractionRing K[X]) :
    ofFractionRing (p + q) = ofFractionRing p + ofFractionRing q := by
  

Proof state:
K : Type u
inst✝ : CommRing K
p q : FractionRing K[X]
⊢ { toFractionRing := p + q } = { toFractionRing := p } + { toFractionRing := q }

Next tactic:
simp only [HAdd.hAdd, Add.add, RatFunc.add]
theorem ofFractionRing_sub (p q : FractionRing K[X]) :
    ofFractionRing (p - q) = ofFractionRing p - ofFractionRing q := by
  

Proof state:
K : Type u
inst✝ : CommRing K
p q : FractionRing K[X]
⊢ { toFractionRing := p - q } = { toFractionRing := p } - { toFractionRing := q }

Next tactic:
simp only [Sub.sub, HSub.hSub, RatFunc.sub]
theorem ofFractionRing_neg (p : FractionRing K[X]) :
    ofFractionRing (-p) = -ofFractionRing p := by 

Proof state:
K : Type u
inst✝ : CommRing K
p : FractionRing K[X]
⊢ { toFractionRing := -p } = -{ toFractionRing := p }

Next tactic:
simp only [Neg.neg, RatFunc.neg]
theorem ofFractionRing_one : (ofFractionRing 1 : RatFunc K) = 1 := by
  

Proof state:
K : Type u
inst✝ : CommRing K
⊢ { toFractionRing := 1 } = 1

Next tactic:
simp only [One.one, OfNat.ofNat, RatFunc.one]
theorem ofFractionRing_mul (p q : FractionRing K[X]) :
    ofFractionRing (p * q) = ofFractionRing p * ofFractionRing q := by
  

Proof state:
K : Type u
inst✝ : CommRing K
p q : FractionRing K[X]
⊢ { toFractionRing := p * q } = { toFractionRing := p } * { toFractionRing := q }

Next tactic:
simp only [Mul.mul, HMul.hMul, RatFunc.mul]
theorem ofFractionRing_div (p q : FractionRing K[X]) :
    ofFractionRing (p / q) = ofFractionRing p / ofFractionRing q := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p q : FractionRing K[X]
⊢ { toFractionRing := p / q } = { toFractionRing := p } / { toFractionRing := q }

Next tactic:
simp only [Div.div, HDiv.hDiv, RatFunc.div]
theorem ofFractionRing_inv (p : FractionRing K[X]) :
    ofFractionRing p⁻¹ = (ofFractionRing p)⁻¹ := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : FractionRing K[X]
⊢ { toFractionRing := p⁻¹ } = { toFractionRing := p }⁻¹

Next tactic:
simp only [Inv.inv, RatFunc.inv]
theorem mul_inv_cancel : ∀ {p : RatFunc K}, p ≠ 0 → p * p⁻¹ = 1
  | ⟨p⟩, h => by
    

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : FractionRing K[X]
h : { toFractionRing := p } ≠ 0
⊢ { toFractionRing := p } * { toFractionRing := p }⁻¹ = 1

Next tactic:
have : p ≠ 0 := fun hp => h <| by rw [hp, ofFractionRing_zero]
theorem mul_inv_cancel : ∀ {p : RatFunc K}, p ≠ 0 → p * p⁻¹ = 1
  | ⟨p⟩, h => by
    have : p ≠ 0 := fun hp => h <| by 

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : FractionRing K[X]
h : { toFractionRing := p } ≠ 0
hp : p = 0
⊢ { toFractionRing := p } = 0

Next tactic:
rw [hp, ofFractionRing_zero]
theorem mul_inv_cancel : ∀ {p : RatFunc K}, p ≠ 0 → p * p⁻¹ = 1
  | ⟨p⟩, h => by
    have : p ≠ 0 := fun hp => h <| by rw [hp, ofFractionRing_zero]
    

Proof state:
K : Type u
inst✝¹ : CommRing K
inst✝ : IsDomain K
p : FractionRing K[X]
h : { toFractionRing := p } ≠ 0
this : p ≠ 0
⊢ { toFractionRing := p } * { toFractionRing := p }⁻¹ = 1

Next tactic:
simpa only [← ofFractionRing_inv, ← ofFractionRing_mul, ← ofFractionRing_one,
      ofFractionRing.injEq] using  -- porting note: `ofFractionRing.injEq` was not present
      _root_.mul_inv_cancel this
theorem ofFractionRing_smul [SMul R (FractionRing K[X])] (c : R) (p : FractionRing K[X]) :
    ofFractionRing (c • p) = c • ofFractionRing p := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
R : Type u_1
inst✝ : SMul R (FractionRing K[X])
c : R
p : FractionRing K[X]
⊢ { toFractionRing := c • p } = c • { toFractionRing := p }

Next tactic:
simp only [SMul.smul, HSMul.hSMul, RatFunc.smul]
theorem toFractionRing_smul [SMul R (FractionRing K[X])] (c : R) (p : RatFunc K) :
    toFractionRing (c • p) = c • toFractionRing p := by
  

Proof state:
K : Type u
inst✝¹ : CommRing K
R : Type u_1
inst✝ : SMul R (FractionRing K[X])
c : R
p : RatFunc K
⊢ (c • p).toFractionRing = c • p.toFractionRing

Next tactic:
cases p
theorem toFractionRing_smul [SMul R (FractionRing K[X])] (c : R) (p : RatFunc K) :
    toFractionRing (c • p) = c • toFractionRing p := by
  cases p
  

Proof state:
case ofFractionRing
K : Type u
inst✝¹ : CommRing K
R : Type u_1
inst✝ : SMul R (FractionRing K[X])
c : R
toFractionRing✝ : FractionRing K[X]
⊢ (c • { toFractionRing := toFractionRing✝ }).toFractionRing = c • { toFractionRing := toFractionRing✝ }.toFractionRing

Next tactic:
rw [← ofFractionRing_smul]
theorem smul_eq_C_smul (x : RatFunc K) (r : K) : r • x = Polynomial.C r • x := by
  

Proof state:
K : Type u
inst✝ : CommRing K
R : Type u_1
x : RatFunc K
r : K
⊢ r • x = Polynomial.C r • x

Next tactic:
cases' x with x
theorem smul_eq_C_smul (x : RatFunc K) (r : K) : r • x = Polynomial.C r • x := by
  cases' x with x
  -- Porting note: had to specify the induction principle manually
  

Proof state:
case ofFractionRing
K : Type u
inst✝ : CommRing K
R : Type u_1
r : K
x : FractionRing K[X]
⊢ r • { toFractionRing := x } = Polynomial.C r • { toFractionRing := x }

Next tactic:
induction x using Localization.induction_on