l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem eval₂_smul (g : R →+* S) (p : R[X]) (x : S) {s : R} :
    eval₂ g x (s • p) = g s * eval₂ g x p := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
g : R →+* S
p : R[X]
x : S
s : R
⊢ eval₂ g x (s • p) = g s * eval₂ g x p

Next tactic:
have A : p.natDegree < p.natDegree.succ := Nat.lt_succ_self _
@[simp]
theorem eval₂_smul (g : R →+* S) (p : R[X]) (x : S) {s : R} :
    eval₂ g x (s • p) = g s * eval₂ g x p := by
  have A : p.natDegree < p.natDegree.succ := Nat.lt_succ_self _
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
g : R →+* S
p : R[X]
x : S
s : R
A : natDegree p < Nat.succ (natDegree p)
⊢ eval₂ g x (s • p) = g s * eval₂ g x p

Next tactic:
have B : (s • p).natDegree < p.natDegree.succ := (natDegree_smul_le _ _).trans_lt A
@[simp]
theorem eval₂_smul (g : R →+* S) (p : R[X]) (x : S) {s : R} :
    eval₂ g x (s • p) = g s * eval₂ g x p := by
  have A : p.natDegree < p.natDegree.succ := Nat.lt_succ_self _
  have B : (s • p).natDegree < p.natDegree.succ := (natDegree_smul_le _ _).trans_lt A
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
g : R →+* S
p : R[X]
x : S
s : R
A : natDegree p < Nat.succ (natDegree p)
B : natDegree (s • p) < Nat.succ (natDegree p)
⊢ eval₂ g x (s • p) = g s * eval₂ g x p

Next tactic:
rw [eval₂_eq_sum, eval₂_eq_sum, sum_over_range' _ _ _ A, sum_over_range' _ _ _ B]
@[simp]
theorem eval₂_smul (g : R →+* S) (p : R[X]) (x : S) {s : R} :
    eval₂ g x (s • p) = g s * eval₂ g x p := by
  have A : p.natDegree < p.natDegree.succ := Nat.lt_succ_self _
  have B : (s • p).natDegree < p.natDegree.succ := (natDegree_smul_le _ _).trans_lt A
  rw [eval₂_eq_sum, eval₂_eq_sum, sum_over_range' _ _ _ A, sum_over_range' _ _ _ B] <;>
    

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
g : R →+* S
p : R[X]
x : S
s : R
A : natDegree p < Nat.succ (natDegree p)
B : natDegree (s • p) < Nat.succ (natDegree p)
⊢ ∑ a in range (Nat.succ (natDegree p)), g (coeff (s • p) a) * x ^ a =
    g s * ∑ a in range (Nat.succ (natDegree p)), g (coeff p a) * x ^ a

Next tactic:
simp [mul_sum, mul_assoc]
@[simp]
theorem eval₂_smul (g : R →+* S) (p : R[X]) (x : S) {s : R} :
    eval₂ g x (s • p) = g s * eval₂ g x p := by
  have A : p.natDegree < p.natDegree.succ := Nat.lt_succ_self _
  have B : (s • p).natDegree < p.natDegree.succ := (natDegree_smul_le _ _).trans_lt A
  rw [eval₂_eq_sum, eval₂_eq_sum, sum_over_range' _ _ _ A, sum_over_range' _ _ _ B] <;>
    

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
g : R →+* S
p : R[X]
x : S
s : R
A : natDegree p < Nat.succ (natDegree p)
B : natDegree (s • p) < Nat.succ (natDegree p)
⊢ ∀ (n : ℕ), g 0 * x ^ n = 0

Next tactic:
simp [mul_sum, mul_assoc]
@[simp]
theorem eval₂_C_X : eval₂ C X p = p :=
  Polynomial.induction_on' p (fun p q hp hq => by 

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q✝ r : R[X]
inst✝ : Semiring S
f : R →+* S
x : S
p q : R[X]
hp : eval₂ C X p = p
hq : eval₂ C X q = q
⊢ eval₂ C X (p + q) = p + q

Next tactic:
simp [hp, hq]
@[simp]
theorem eval₂_C_X : eval₂ C X p = p :=
  Polynomial.induction_on' p (fun p q hp hq => by simp [hp, hq]) fun n x => by
    

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p q r : R[X]
inst✝ : Semiring S
f : R →+* S
x✝ : S
n : ℕ
x : R
⊢ eval₂ C X ((monomial n) x) = (monomial n) x

Next tactic:
rw [eval₂_monomial, ← smul_X_eq_monomial, C_mul']
@[simp]
theorem eval₂_nat_cast (n : ℕ) : (n : R[X]).eval₂ f x = n := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p q r : R[X]
inst✝ : Semiring S
f : R →+* S
x : S
n : ℕ
⊢ eval₂ f x ↑n = ↑n

Next tactic:
induction' n with n ih
@[simp]
theorem eval₂_nat_cast (n : ℕ) : (n : R[X]).eval₂ f x = n := by
  induction' n with n ih
  -- Porting note: `Nat.zero_eq` is required.
  · 

Proof state:
case zero
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p q r : R[X]
inst✝ : Semiring S
f : R →+* S
x : S
⊢ eval₂ f x ↑Nat.zero = ↑Nat.zero

Next tactic:
simp only [eval₂_zero, Nat.cast_zero, Nat.zero_eq]
@[simp]
theorem eval₂_nat_cast (n : ℕ) : (n : R[X]).eval₂ f x = n := by
  induction' n with n ih
  -- Porting note: `Nat.zero_eq` is required.
  · simp only [eval₂_zero, Nat.cast_zero, Nat.zero_eq]
  · 

Proof state:
case succ
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p q r : R[X]
inst✝ : Semiring S
f : R →+* S
x : S
n : ℕ
ih : eval₂ f x ↑n = ↑n
⊢ eval₂ f x ↑(Nat.succ n) = ↑(Nat.succ n)

Next tactic:
rw [n.cast_succ, eval₂_add, ih, eval₂_one, n.cast_succ]
@[simp]
lemma eval₂_ofNat {S : Type*} [Semiring S] (n : ℕ) [n.AtLeastTwo] (f : R →+* S) (a : S) :
    (no_index (OfNat.ofNat n : R[X])).eval₂ f a = OfNat.ofNat n := by
  

Proof state:
R : Type u
S✝ : Type v
T : Type w
ι : Type y
a✝ b : R
m n✝ : ℕ
inst✝³ : Semiring R
p q r : R[X]
inst✝² : Semiring S✝
f✝ : R →+* S✝
x : S✝
S : Type u_1
inst✝¹ : Semiring S
n : ℕ
inst✝ : Nat.AtLeastTwo n
f : R →+* S
a : S
⊢ eval₂ f a (OfNat.ofNat n) = OfNat.ofNat n

Next tactic:
simp [OfNat.ofNat]
theorem eval₂_sum (p : T[X]) (g : ℕ → T → R[X]) (x : S) :
    (p.sum g).eval₂ f x = p.sum fun n a => (g n a).eval₂ f x := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x✝ : S
inst✝ : Semiring T
p : T[X]
g : ℕ → T → R[X]
x : S
⊢ eval₂ f x (sum p g) = sum p fun n a => eval₂ f x (g n a)

Next tactic:
let T : R[X] →+ S :=
    { toFun := eval₂ f x
      map_zero' := eval₂_zero _ _
      map_add' := fun p q => eval₂_add _ _ }
theorem eval₂_sum (p : T[X]) (g : ℕ → T → R[X]) (x : S) :
    (p.sum g).eval₂ f x = p.sum fun n a => (g n a).eval₂ f x := by
  let T : R[X] →+ S :=
    { toFun := eval₂ f x
      map_zero' := eval₂_zero _ _
      map_add' := fun p q => eval₂_add _ _ }
  

Proof state:
R : Type u
S : Type v
T✝ : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x✝ : S
inst✝ : Semiring T✝
p : T✝[X]
g : ℕ → T✝ → R[X]
x : S
T : R[X] →+ S :=
  { toZeroHom := { toFun := eval₂ f x, map_zero' := (_ : eval₂ f x 0 = 0) },
    map_add' := (_ : ∀ (p q : R[X]), eval₂ f x (p + q) = eval₂ f x p + eval₂ f x q) }
⊢ eval₂ f x (sum p g) = sum p fun n a => eval₂ f x (g n a)

Next tactic:
have A : ∀ y, eval₂ f x y = T y := fun y => rfl
theorem eval₂_sum (p : T[X]) (g : ℕ → T → R[X]) (x : S) :
    (p.sum g).eval₂ f x = p.sum fun n a => (g n a).eval₂ f x := by
  let T : R[X] →+ S :=
    { toFun := eval₂ f x
      map_zero' := eval₂_zero _ _
      map_add' := fun p q => eval₂_add _ _ }
  have A : ∀ y, eval₂ f x y = T y := fun y => rfl
  

Proof state:
R : Type u
S : Type v
T✝ : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x✝ : S
inst✝ : Semiring T✝
p : T✝[X]
g : ℕ → T✝ → R[X]
x : S
T : R[X] →+ S :=
  { toZeroHom := { toFun := eval₂ f x, map_zero' := (_ : eval₂ f x 0 = 0) },
    map_add' := (_ : ∀ (p q : R[X]), eval₂ f x (p + q) = eval₂ f x p + eval₂ f x q) }
A : ∀ (y : R[X]), eval₂ f x y = T y
⊢ eval₂ f x (sum p g) = sum p fun n a => eval₂ f x (g n a)

Next tactic:
simp only [A]
theorem eval₂_sum (p : T[X]) (g : ℕ → T → R[X]) (x : S) :
    (p.sum g).eval₂ f x = p.sum fun n a => (g n a).eval₂ f x := by
  let T : R[X] →+ S :=
    { toFun := eval₂ f x
      map_zero' := eval₂_zero _ _
      map_add' := fun p q => eval₂_add _ _ }
  have A : ∀ y, eval₂ f x y = T y := fun y => rfl
  simp only [A]
  

Proof state:
R : Type u
S : Type v
T✝ : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x✝ : S
inst✝ : Semiring T✝
p : T✝[X]
g : ℕ → T✝ → R[X]
x : S
T : R[X] →+ S :=
  { toZeroHom := { toFun := eval₂ f x, map_zero' := (_ : eval₂ f x 0 = 0) },
    map_add' := (_ : ∀ (p q : R[X]), eval₂ f x (p + q) = eval₂ f x p + eval₂ f x q) }
A : ∀ (y : R[X]), eval₂ f x y = T y
⊢ { toZeroHom := { toFun := eval₂ f x, map_zero' := (_ : eval₂ f x 0 = 0) },
        map_add' := (_ : ∀ (p q : R[X]), eval₂ f x (p + q) = eval₂ f x p + eval₂ f x q) }
      (sum p g) =
    sum p fun n a =>
      { toZeroHom := { toFun := eval₂ f x, map_zero' := (_ : eval₂ f x 0 = 0) },
          map_add' := (_ : ∀ (p q : R[X]), eval₂ f x (p + q) = eval₂ f x p + eval₂ f x q) }
        (g n a)

Next tactic:
rw [sum, map_sum, sum]
theorem eval₂_ofFinsupp {f : R →+* S} {x : S} {p : R[ℕ]} :
    eval₂ f x (⟨p⟩ : R[X]) = liftNC (↑f) (powersHom S x) p := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f✝ : R →+* S
x✝ : S
inst✝ : Semiring T
f : R →+* S
x : S
p : R[ℕ]
⊢ eval₂ f x { toFinsupp := p } = (liftNC ↑f ⇑((powersHom S) x)) p

Next tactic:
simp only [eval₂_eq_sum, sum, toFinsupp_sum, support, coeff]
theorem eval₂_ofFinsupp {f : R →+* S} {x : S} {p : R[ℕ]} :
    eval₂ f x (⟨p⟩ : R[X]) = liftNC (↑f) (powersHom S x) p := by
  simp only [eval₂_eq_sum, sum, toFinsupp_sum, support, coeff]
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f✝ : R →+* S
x✝ : S
inst✝ : Semiring T
f : R →+* S
x : S
p : R[ℕ]
⊢ ∑ x_1 in p.support, f (p x_1) * x ^ x_1 = (liftNC ↑f ⇑((powersHom S) x)) p

Next tactic:
rfl
theorem eval₂_mul_noncomm (hf : ∀ k, Commute (f <| q.coeff k) x) :
    eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
hf : ∀ (k : ℕ), Commute (f (coeff q k)) x
⊢ eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q

Next tactic:
rcases p with ⟨p⟩
theorem eval₂_mul_noncomm (hf : ∀ k, Commute (f <| q.coeff k) x) :
    eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q := by
  rcases p with ⟨p⟩; 

Proof state:
case ofFinsupp
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
hf : ∀ (k : ℕ), Commute (f (coeff q k)) x
p : R[ℕ]
⊢ eval₂ f x ({ toFinsupp := p } * q) = eval₂ f x { toFinsupp := p } * eval₂ f x q

Next tactic:
rcases q with ⟨q⟩
theorem eval₂_mul_noncomm (hf : ∀ k, Commute (f <| q.coeff k) x) :
    eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q := by
  rcases p with ⟨p⟩; rcases q with ⟨q⟩
  

Proof state:
case ofFinsupp.ofFinsupp
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
p q : R[ℕ]
hf : ∀ (k : ℕ), Commute (f (coeff { toFinsupp := q } k)) x
⊢ eval₂ f x ({ toFinsupp := p } * { toFinsupp := q }) = eval₂ f x { toFinsupp := p } * eval₂ f x { toFinsupp := q }

Next tactic:
simp only [coeff] at hf
theorem eval₂_mul_noncomm (hf : ∀ k, Commute (f <| q.coeff k) x) :
    eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q := by
  rcases p with ⟨p⟩; rcases q with ⟨q⟩
  simp only [coeff] at hf
  

Proof state:
case ofFinsupp.ofFinsupp
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
p q : R[ℕ]
hf : ∀ (k : ℕ), Commute (f (q k)) x
⊢ eval₂ f x ({ toFinsupp := p } * { toFinsupp := q }) = eval₂ f x { toFinsupp := p } * eval₂ f x { toFinsupp := q }

Next tactic:
simp only [← ofFinsupp_mul, eval₂_ofFinsupp]
theorem eval₂_mul_noncomm (hf : ∀ k, Commute (f <| q.coeff k) x) :
    eval₂ f x (p * q) = eval₂ f x p * eval₂ f x q := by
  rcases p with ⟨p⟩; rcases q with ⟨q⟩
  simp only [coeff] at hf
  simp only [← ofFinsupp_mul, eval₂_ofFinsupp]
  

Proof state:
case ofFinsupp.ofFinsupp
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
p q : R[ℕ]
hf : ∀ (k : ℕ), Commute (f (q k)) x
⊢ (liftNC ↑f ⇑((powersHom S) x)) (p * q) = (liftNC ↑f ⇑((powersHom S) x)) p * (liftNC ↑f ⇑((powersHom S) x)) q

Next tactic:
exact liftNC_mul _ _ p q fun {k n} _hn => (hf k).pow_right n
@[simp]
theorem eval₂_mul_X : eval₂ f x (p * X) = eval₂ f x p * x := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
⊢ eval₂ f x (p * X) = eval₂ f x p * x

Next tactic:
refine' _root_.trans (eval₂_mul_noncomm _ _ fun k => _) (by rw [eval₂_X])
@[simp]
theorem eval₂_mul_X : eval₂ f x (p * X) = eval₂ f x p * x := by
  refine' _root_.trans (eval₂_mul_noncomm _ _ fun k => _) (by 

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
⊢ eval₂ f x p * eval₂ f x X = eval₂ f x p * x

Next tactic:
rw [eval₂_X]
@[simp]
theorem eval₂_mul_X : eval₂ f x (p * X) = eval₂ f x p * x := by
  refine' _root_.trans (eval₂_mul_noncomm _ _ fun k => _) (by rw [eval₂_X])
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
k : ℕ
⊢ Commute (f (coeff X k)) x

Next tactic:
rcases em (k = 1) with (rfl | hk)
@[simp]
theorem eval₂_mul_X : eval₂ f x (p * X) = eval₂ f x p * x := by
  refine' _root_.trans (eval₂_mul_noncomm _ _ fun k => _) (by rw [eval₂_X])
  rcases em (k = 1) with (rfl | hk)
  · 

Proof state:
case inl
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
⊢ Commute (f (coeff X 1)) x

Next tactic:
simp
@[simp]
theorem eval₂_mul_X : eval₂ f x (p * X) = eval₂ f x p * x := by
  refine' _root_.trans (eval₂_mul_noncomm _ _ fun k => _) (by rw [eval₂_X])
  rcases em (k = 1) with (rfl | hk)
  · simp
  · 

Proof state:
case inr
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
k : ℕ
hk : ¬k = 1
⊢ Commute (f (coeff X k)) x

Next tactic:
simp [coeff_X_of_ne_one hk]
@[simp]
theorem eval₂_X_mul : eval₂ f x (X * p) = eval₂ f x p * x := by 

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
⊢ eval₂ f x (X * p) = eval₂ f x p * x

Next tactic:
rw [X_mul, eval₂_mul_X]
theorem eval₂_mul_C' (h : Commute (f a) x) : eval₂ f x (p * C a) = eval₂ f x p * f a := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
h : Commute (f a) x
⊢ eval₂ f x (p * C a) = eval₂ f x p * f a

Next tactic:
rw [eval₂_mul_noncomm, eval₂_C]
theorem eval₂_mul_C' (h : Commute (f a) x) : eval₂ f x (p * C a) = eval₂ f x p * f a := by
  rw [eval₂_mul_noncomm, eval₂_C]
  

Proof state:
case hf
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
h : Commute (f a) x
⊢ ∀ (k : ℕ), Commute (f (coeff (C a) k)) x

Next tactic:
intro k
theorem eval₂_mul_C' (h : Commute (f a) x) : eval₂ f x (p * C a) = eval₂ f x p * f a := by
  rw [eval₂_mul_noncomm, eval₂_C]
  intro k
  

Proof state:
case hf
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
h : Commute (f a) x
k : ℕ
⊢ Commute (f (coeff (C a) k)) x

Next tactic:
by_cases hk : k = 0
theorem eval₂_mul_C' (h : Commute (f a) x) : eval₂ f x (p * C a) = eval₂ f x p * f a := by
  rw [eval₂_mul_noncomm, eval₂_C]
  intro k
  by_cases hk : k = 0
  · 

Proof state:
case pos
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
h : Commute (f a) x
k : ℕ
hk : k = 0
⊢ Commute (f (coeff (C a) k)) x

Next tactic:
simp only [hk, h, coeff_C_zero, coeff_C_ne_zero]
theorem eval₂_mul_C' (h : Commute (f a) x) : eval₂ f x (p * C a) = eval₂ f x p * f a := by
  rw [eval₂_mul_noncomm, eval₂_C]
  intro k
  by_cases hk : k = 0
  · simp only [hk, h, coeff_C_zero, coeff_C_ne_zero]
  · 

Proof state:
case neg
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
h : Commute (f a) x
k : ℕ
hk : ¬k = 0
⊢ Commute (f (coeff (C a) k)) x

Next tactic:
simp only [coeff_C_ne_zero hk, RingHom.map_zero, Commute.zero_left]
theorem eval₂_list_prod_noncomm (ps : List R[X])
    (hf : ∀ p ∈ ps, ∀ (k), Commute (f <| coeff p k) x) :
    eval₂ f x ps.prod = (ps.map (Polynomial.eval₂ f x)).prod := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
ps : List R[X]
hf : ∀ p ∈ ps, ∀ (k : ℕ), Commute (f (coeff p k)) x
⊢ eval₂ f x (List.prod ps) = List.prod (List.map (eval₂ f x) ps)

Next tactic:
induction' ps using List.reverseRecOn with ps p ihp
theorem eval₂_list_prod_noncomm (ps : List R[X])
    (hf : ∀ p ∈ ps, ∀ (k), Commute (f <| coeff p k) x) :
    eval₂ f x ps.prod = (ps.map (Polynomial.eval₂ f x)).prod := by
  induction' ps using List.reverseRecOn with ps p ihp
  · 

Proof state:
case H0
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
hf : ∀ p ∈ [], ∀ (k : ℕ), Commute (f (coeff p k)) x
⊢ eval₂ f x (List.prod []) = List.prod (List.map (eval₂ f x) [])

Next tactic:
simp
theorem eval₂_list_prod_noncomm (ps : List R[X])
    (hf : ∀ p ∈ ps, ∀ (k), Commute (f <| coeff p k) x) :
    eval₂ f x ps.prod = (ps.map (Polynomial.eval₂ f x)).prod := by
  induction' ps using List.reverseRecOn with ps p ihp
  · simp
  · 

Proof state:
case H1
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
ps : List R[X]
p : R[X]
ihp : (∀ p ∈ ps, ∀ (k : ℕ), Commute (f (coeff p k)) x) → eval₂ f x (List.prod ps) = List.prod (List.map (eval₂ f x) ps)
hf : ∀ p_1 ∈ ps ++ [p], ∀ (k : ℕ), Commute (f (coeff p_1 k)) x
⊢ eval₂ f x (List.prod (ps ++ [p])) = List.prod (List.map (eval₂ f x) (ps ++ [p]))

Next tactic:
simp only [List.forall_mem_append, List.forall_mem_singleton] at hf
theorem eval₂_list_prod_noncomm (ps : List R[X])
    (hf : ∀ p ∈ ps, ∀ (k), Commute (f <| coeff p k) x) :
    eval₂ f x ps.prod = (ps.map (Polynomial.eval₂ f x)).prod := by
  induction' ps using List.reverseRecOn with ps p ihp
  · simp
  · simp only [List.forall_mem_append, List.forall_mem_singleton] at hf
    

Proof state:
case H1
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝² : Semiring R
p✝ q r : R[X]
inst✝¹ : Semiring S
f : R →+* S
x : S
inst✝ : Semiring T
ps : List R[X]
p : R[X]
ihp : (∀ p ∈ ps, ∀ (k : ℕ), Commute (f (coeff p k)) x) → eval₂ f x (List.prod ps) = List.prod (List.map (eval₂ f x) ps)
hf : (∀ x_1 ∈ ps, ∀ (k : ℕ), Commute (f (coeff x_1 k)) x) ∧ ∀ (k : ℕ), Commute (f (coeff p k)) x
⊢ eval₂ f x (List.prod (ps ++ [p])) = List.prod (List.map (eval₂ f x) (ps ++ [p]))

Next tactic:
simp [eval₂_mul_noncomm _ _ hf.2, ihp hf.1]
theorem eval₂_eq_sum_range :
    p.eval₂ f x = ∑ i in Finset.range (p.natDegree + 1), f (p.coeff i) * x ^ i :=
  _root_.trans (congr_arg _ p.as_sum_range)
    (_root_.trans (eval₂_finset_sum f _ _ x) (congr_arg _ (by 

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p q r : R[X]
inst✝ : Semiring S
f : R →+* S
x : S
⊢ (fun i => eval₂ f x ((monomial i) (coeff p i))) = fun i => f (coeff p i) * x ^ i

Next tactic:
simp
theorem eval₂_eq_sum_range' (f : R →+* S) {p : R[X]} {n : ℕ} (hn : p.natDegree < n) (x : S) :
    eval₂ f x p = ∑ i in Finset.range n, f (p.coeff i) * x ^ i := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f✝ : R →+* S
x✝ : S
f : R →+* S
p : R[X]
n : ℕ
hn : natDegree p < n
x : S
⊢ eval₂ f x p = ∑ i in range n, f (coeff p i) * x ^ i

Next tactic:
rw [eval₂_eq_sum, p.sum_over_range' _ _ hn]
theorem eval₂_eq_sum_range' (f : R →+* S) {p : R[X]} {n : ℕ} (hn : p.natDegree < n) (x : S) :
    eval₂ f x p = ∑ i in Finset.range n, f (p.coeff i) * x ^ i := by
  rw [eval₂_eq_sum, p.sum_over_range' _ _ hn]
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f✝ : R →+* S
x✝ : S
f : R →+* S
p : R[X]
n : ℕ
hn : natDegree p < n
x : S
⊢ ∀ (n : ℕ), f 0 * x ^ n = 0

Next tactic:
intro i
theorem eval₂_eq_sum_range' (f : R →+* S) {p : R[X]} {n : ℕ} (hn : p.natDegree < n) (x : S) :
    eval₂ f x p = ∑ i in Finset.range n, f (p.coeff i) * x ^ i := by
  rw [eval₂_eq_sum, p.sum_over_range' _ _ hn]
  intro i
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n✝ : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : Semiring S
f✝ : R →+* S
x✝ : S
f : R →+* S
p : R[X]
n : ℕ
hn : natDegree p < n
x : S
i : ℕ
⊢ f 0 * x ^ i = 0

Next tactic:
rw [f.map_zero, zero_mul]
theorem eval₂_mul_eq_zero_of_left (q : R[X]) (hp : p.eval₂ f x = 0) : (p * q).eval₂ f x = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p q✝ r : R[X]
inst✝ : CommSemiring S
f : R →+* S
x : S
q : R[X]
hp : eval₂ f x p = 0
⊢ eval₂ f x (p * q) = 0

Next tactic:
rw [eval₂_mul f x]
theorem eval₂_mul_eq_zero_of_left (q : R[X]) (hp : p.eval₂ f x = 0) : (p * q).eval₂ f x = 0 := by
  rw [eval₂_mul f x]
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p q✝ r : R[X]
inst✝ : CommSemiring S
f : R →+* S
x : S
q : R[X]
hp : eval₂ f x p = 0
⊢ eval₂ f x p * eval₂ f x q = 0

Next tactic:
exact mul_eq_zero_of_left hp (q.eval₂ f x)
theorem eval₂_mul_eq_zero_of_right (p : R[X]) (hq : q.eval₂ f x = 0) : (p * q).eval₂ f x = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : CommSemiring S
f : R →+* S
x : S
p : R[X]
hq : eval₂ f x q = 0
⊢ eval₂ f x (p * q) = 0

Next tactic:
rw [eval₂_mul f x]
theorem eval₂_mul_eq_zero_of_right (p : R[X]) (hq : q.eval₂ f x = 0) : (p * q).eval₂ f x = 0 := by
  rw [eval₂_mul f x]
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝¹ : Semiring R
p✝ q r : R[X]
inst✝ : CommSemiring S
f : R →+* S
x : S
p : R[X]
hq : eval₂ f x q = 0
⊢ eval₂ f x p * eval₂ f x q = 0

Next tactic:
exact mul_eq_zero_of_right (p.eval₂ f x) hq
theorem eval_eq_sum : p.eval x = p.sum fun e a => a * x ^ e := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
x : R
⊢ eval x p = sum p fun e a => a * x ^ e

Next tactic:
rw [eval, eval₂_eq_sum]
theorem eval_eq_sum : p.eval x = p.sum fun e a => a * x ^ e := by
  rw [eval, eval₂_eq_sum]
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝ : Semiring R
p q r : R[X]
x : R
⊢ (sum p fun e a => (RingHom.id R) a * x ^ e) = sum p fun e a => a * x ^ e

Next tactic:
rfl
theorem eval_eq_sum_range {p : R[X]} (x : R) :
    p.eval x = ∑ i in Finset.range (p.natDegree + 1), p.coeff i * x ^ i := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
x✝ : R
p : R[X]
x : R
⊢ eval x p = ∑ i in range (natDegree p + 1), coeff p i * x ^ i

Next tactic:
rw [eval_eq_sum, sum_over_range]
theorem eval_eq_sum_range {p : R[X]} (x : R) :
    p.eval x = ∑ i in Finset.range (p.natDegree + 1), p.coeff i * x ^ i := by
  rw [eval_eq_sum, sum_over_range]; 

Proof state:
case h
R : Type u
S : Type v
T : Type w
ι : Type y
a b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
x✝ : R
p : R[X]
x : R
⊢ ∀ (n : ℕ), 0 * x ^ n = 0

Next tactic:
simp