l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem aevalTower_id : aevalTower (AlgHom.id S S) = aeval := by
  ext s
  

Proof state:
case h.hX
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝¹⁰ : CommSemiring R
inst✝⁹ : Semiring A
inst✝⁸ : CommSemiring A'
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R A
inst✝⁵ : Algebra R A'
inst✝⁴ : Algebra R B
p q : R[X]
x : A
inst✝³ : CommSemiring S
inst✝² : Algebra S R
inst✝¹ : Algebra S A'
inst✝ : Algebra S B
g : R →ₐ[S] A'
y : A'
s : S
⊢ (aevalTower (AlgHom.id S S) s) X = (aeval s) X

Next tactic:
simp only [eval_X, aevalTower_X, coe_aeval_eq_eval]
@[simp]
theorem aevalTower_ofId : aevalTower (Algebra.ofId S A') = aeval := by
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝¹⁰ : CommSemiring R
inst✝⁹ : Semiring A
inst✝⁸ : CommSemiring A'
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R A
inst✝⁵ : Algebra R A'
inst✝⁴ : Algebra R B
p q : R[X]
x : A
inst✝³ : CommSemiring S
inst✝² : Algebra S R
inst✝¹ : Algebra S A'
inst✝ : Algebra S B
g : R →ₐ[S] A'
y : A'
⊢ aevalTower (Algebra.ofId S A') = aeval

Next tactic:
ext
@[simp]
theorem aevalTower_ofId : aevalTower (Algebra.ofId S A') = aeval := by
  ext
  

Proof state:
case h.hX
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝¹⁰ : CommSemiring R
inst✝⁹ : Semiring A
inst✝⁸ : CommSemiring A'
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R A
inst✝⁵ : Algebra R A'
inst✝⁴ : Algebra R B
p q : R[X]
x : A
inst✝³ : CommSemiring S
inst✝² : Algebra S R
inst✝¹ : Algebra S A'
inst✝ : Algebra S B
g : R →ₐ[S] A'
y x✝ : A'
⊢ (aevalTower (Algebra.ofId S A') x✝) X = (aeval x✝) X

Next tactic:
simp only [aeval_X, aevalTower_X]
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ eval z f
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
⊢ p ∣ coeff f i * z ^ i

Next tactic:
by_cases hi : i ∈ f.support
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · 

Proof state:
case pos
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ eval z f
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
⊢ p ∣ coeff f i * z ^ i

Next tactic:
rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    

Proof state:
case pos
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ ∑ n in support f, (RingHom.id S) (coeff f n) * z ^ n
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
⊢ p ∣ coeff f i * z ^ i

Next tactic:
rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    

Proof state:
case pos
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval :
  p ∣ (RingHom.id S) (coeff f i) * z ^ i + ∑ x in Finset.erase (support f) i, (RingHom.id S) (coeff f x) * z ^ x
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
⊢ p ∣ coeff f i * z ^ i

Next tactic:
refine' (dvd_add_left _).mp dvd_eval
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    

Proof state:
case pos
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval :
  p ∣ (RingHom.id S) (coeff f i) * z ^ i + ∑ x in Finset.erase (support f) i, (RingHom.id S) (coeff f x) * z ^ x
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
⊢ p ∣ ∑ x in Finset.erase (support f) i, (RingHom.id S) (coeff f x) * z ^ x

Next tactic:
apply Finset.dvd_sum
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    apply Finset.dvd_sum
    

Proof state:
case pos.h
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval :
  p ∣ (RingHom.id S) (coeff f i) * z ^ i + ∑ x in Finset.erase (support f) i, (RingHom.id S) (coeff f x) * z ^ x
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
⊢ ∀ x ∈ Finset.erase (support f) i, p ∣ (RingHom.id S) (coeff f x) * z ^ x

Next tactic:
intro j hj
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    apply Finset.dvd_sum
    intro j hj
    

Proof state:
case pos.h
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval :
  p ∣ (RingHom.id S) (coeff f i) * z ^ i + ∑ x in Finset.erase (support f) i, (RingHom.id S) (coeff f x) * z ^ x
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∈ support f
j : ℕ
hj : j ∈ Finset.erase (support f) i
⊢ p ∣ (RingHom.id S) (coeff f j) * z ^ j

Next tactic:
exact dvd_terms j (Finset.ne_of_mem_erase hj)
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    apply Finset.dvd_sum
    intro j hj
    exact dvd_terms j (Finset.ne_of_mem_erase hj)
  · 

Proof state:
case neg
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ eval z f
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∉ support f
⊢ p ∣ coeff f i * z ^ i

Next tactic:
convert dvd_zero p
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    apply Finset.dvd_sum
    intro j hj
    exact dvd_terms j (Finset.ne_of_mem_erase hj)
  · convert dvd_zero p
    

Proof state:
case h.e'_4
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ eval z f
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : i ∉ support f
⊢ coeff f i * z ^ i = 0

Next tactic:
rw [not_mem_support_iff] at hi
theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z)
    (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by
  by_cases hi : i ∈ f.support
  · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval
    rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval
    refine' (dvd_add_left _).mp dvd_eval
    apply Finset.dvd_sum
    intro j hj
    exact dvd_terms j (Finset.ne_of_mem_erase hj)
  · convert dvd_zero p
    rw [not_mem_support_iff] at hi
    

Proof state:
case h.e'_4
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝⁷ : CommSemiring R
inst✝⁶ : Semiring A
inst✝⁵ : CommSemiring A'
inst✝⁴ : Semiring B
inst✝³ : Algebra R A
inst✝² : Algebra R A'
inst✝¹ : Algebra R B
p✝ q : R[X]
x : A
inst✝ : CommRing S
f✝ : R →+* S
z p : S
f : S[X]
i : ℕ
dvd_eval : p ∣ eval z f
dvd_terms : ∀ (j : ℕ), j ≠ i → p ∣ coeff f j * z ^ j
hi : coeff f i = 0
⊢ coeff f i * z ^ i = 0

Next tactic:
simp [hi]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
⊢ eval r (p * (X - C r)) = 0

Next tactic:
simp only [eval, eval₂_eq_sum, RingHom.id_apply]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
⊢ (sum (p * (X - C r)) fun e a => a * r ^ e) = 0

Next tactic:
have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ (sum (p * (X - C r)) fun e a => a * r ^ e) = 0

Next tactic:
rw [sum_over_range' _ _ (p.natDegree + 2) bound]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∑ a in range (natDegree p + 2), coeff (p * (X - C r)) a * r ^ a = 0
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∀ (n : ℕ), 0 * r ^ n = 0

Next tactic:
swap
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · 

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∀ (n : ℕ), 0 * r ^ n = 0

Next tactic:
simp
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∑ a in range (natDegree p + 2), coeff (p * (X - C r)) a * r ^ a = 0

Next tactic:
rw [sum_range_succ']
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∑ k in range (natDegree p + 1), coeff (p * (X - C r)) (k + 1) * r ^ (k + 1) + coeff (p * (X - C r)) 0 * r ^ 0 = 0

Next tactic:
conv_lhs =>
    congr
    arg 2
    simp [coeff_mul_X_sub_C, sub_mul, mul_assoc, ← pow_succ]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| ∑ k in range (natDegree p + 1), coeff (p * (X - C r)) (k + 1) * r ^ (k + 1) + coeff (p * (X - C r)) 0 * r ^ 0

Next tactic:
congr
    arg 2
    simp [coeff_mul_X_sub_C, sub_mul, mul_assoc, ← pow_succ]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| ∑ k in range (natDegree p + 1), coeff (p * (X - C r)) (k + 1) * r ^ (k + 1) + coeff (p * (X - C r)) 0 * r ^ 0

Next tactic:
congr
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    congr
    

Proof state:
case a
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| ∑ k in range (natDegree p + 1), coeff (p * (X - C r)) (k + 1) * r ^ (k + 1)
case a
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| coeff (p * (X - C r)) 0 * r ^ 0

Next tactic:
arg 2
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    congr
    arg 2
    

Proof state:
case a
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| fun k => coeff (p * (X - C r)) (k + 1) * r ^ (k + 1)
case a
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
| coeff (p * (X - C r)) 0 * r ^ 0

Next tactic:
simp [coeff_mul_X_sub_C, sub_mul, mul_assoc, ← pow_succ]
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    congr
    arg 2
    simp [coeff_mul_X_sub_C, sub_mul, mul_assoc, ← pow_succ]
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ ∑ k in range (natDegree p + 1), (coeff p k * r ^ (k + 1) - coeff p (k + 1) * r ^ (k + 1 + 1)) +
      coeff (p * (X - C r)) 0 * r ^ 0 =
    0

Next tactic:
rw [sum_range_sub']