l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem expand_aeval {A : Type*} [Semiring A] [Algebra R A] (p : ℕ) (P : R[X]) (r : A) :
    aeval r (expand R p P) = aeval (r ^ p) P := by
  refine' Polynomial.induction_on P (fun a => by simp) (fun f g hf hg => _) fun n a _ => by simp
  

Proof state:
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p✝ q : ℕ
A : Type u_1
inst✝¹ : Semiring A
inst✝ : Algebra R A
p : ℕ
P : R[X]
r : A
f g : R[X]
hf : (aeval r) ((expand R p) f) = (aeval (r ^ p)) f
hg : (aeval r) ((expand R p) g) = (aeval (r ^ p)) g
⊢ (aeval r) ((expand R p) (f + g)) = (aeval (r ^ p)) (f + g)

Next tactic:
rw [AlgHom.map_add, aeval_add, aeval_add, hf, hg]
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
    (contract p f).coeff n = f.coeff (n * p) := by
  

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p✝ q p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
⊢ coeff (contract p f) n = coeff f (n * p)

Next tactic:
simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
    ite_eq_left_iff]
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
    (contract p f).coeff n = f.coeff (n * p) := by
  simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
    ite_eq_left_iff]
  

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p✝ q p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
⊢ natDegree f + 1 ≤ n → 0 = coeff f (n * p)

Next tactic:
intro hn
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
    (contract p f).coeff n = f.coeff (n * p) := by
  simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
    ite_eq_left_iff]
  intro hn
  

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p✝ q p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
hn : natDegree f + 1 ≤ n
⊢ 0 = coeff f (n * p)

Next tactic:
apply (coeff_eq_zero_of_natDegree_lt _).symm
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
    (contract p f).coeff n = f.coeff (n * p) := by
  simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
    ite_eq_left_iff]
  intro hn
  apply (coeff_eq_zero_of_natDegree_lt _).symm
  

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p✝ q p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
hn : natDegree f + 1 ≤ n
⊢ natDegree f < n * p

Next tactic:
calc
    f.natDegree < f.natDegree + 1 := Nat.lt_succ_self _
    _ ≤ n * 1 := by simpa only [mul_one] using hn
    _ ≤ n * p := mul_le_mul_of_nonneg_left (show 1 ≤ p from hp.bot_lt) (zero_le n)
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
    (contract p f).coeff n = f.coeff (n * p) := by
  simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
    ite_eq_left_iff]
  intro hn
  apply (coeff_eq_zero_of_natDegree_lt _).symm
  calc
    f.natDegree < f.natDegree + 1 := Nat.lt_succ_self _
    _ ≤ n * 1 := by 

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p✝ q p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
hn : natDegree f + 1 ≤ n
⊢ natDegree f + 1 ≤ n * 1

Next tactic:
simpa only [mul_one] using hn
theorem contract_expand {f : R[X]} (hp : p ≠ 0) : contract p (expand R p f) = f := by
  

Proof state:
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p q : ℕ
f : R[X]
hp : p ≠ 0
⊢ contract p ((expand R p) f) = f

Next tactic:
ext
theorem contract_expand {f : R[X]} (hp : p ≠ 0) : contract p (expand R p f) = f := by
  ext
  

Proof state:
case a
R : Type u
inst✝¹ : CommSemiring R
S : Type v
inst✝ : CommSemiring S
p q : ℕ
f : R[X]
hp : p ≠ 0
n✝ : ℕ
⊢ coeff (contract p ((expand R p) f)) n✝ = coeff f n✝

Next tactic:
simp [coeff_contract hp, coeff_expand hp.bot_lt, Nat.mul_div_cancel _ hp.bot_lt]
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  

Proof state:
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
⊢ (expand R p) (contract p f) = f

Next tactic:
ext n
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  

Proof state:
case a
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
⊢ coeff ((expand R p) (contract p f)) n = coeff f n

Next tactic:
rw [coeff_expand hp.bot_lt, coeff_contract hp]
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  

Proof state:
case a
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
⊢ (if p ∣ n then coeff f (n / p * p) else 0) = coeff f n

Next tactic:
split_ifs with h
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · 

Proof state:
case pos
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : p ∣ n
⊢ coeff f (n / p * p) = coeff f n

Next tactic:
rw [Nat.div_mul_cancel h]
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · 

Proof state:
case neg
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ n
⊢ 0 = coeff f n

Next tactic:
cases' n with n
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · 

Proof state:
case neg.zero
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
h : ¬p ∣ Nat.zero
⊢ 0 = coeff f Nat.zero

Next tactic:
exact absurd (dvd_zero p) h
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    

Proof state:
case neg.succ
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
have := coeff_derivative f n
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    

Proof state:
case neg.succ
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
this : coeff (derivative f) n = coeff f (n + 1) * (↑n + 1)
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
rw [hf, coeff_zero, zero_eq_mul] at this
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    rw [hf, coeff_zero, zero_eq_mul] at this
    

Proof state:
case neg.succ
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
this : coeff f (n + 1) = 0 ∨ ↑n + 1 = 0
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
cases' this with h'
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    rw [hf, coeff_zero, zero_eq_mul] at this
    cases' this with h'
    · 

Proof state:
case neg.succ.inl
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
h' : coeff f (n + 1) = 0
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
rw [h']
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    rw [hf, coeff_zero, zero_eq_mul] at this
    cases' this with h'
    · rw [h']
    

Proof state:
case neg.succ.inr
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
h✝ : ↑n + 1 = 0
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
rename_i _ _ _ _ h'
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    rw [hf, coeff_zero, zero_eq_mul] at this
    cases' this with h'
    · rw [h']
    rename_i _ _ _ _ h'
    

Proof state:
case neg.succ.inr
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
h' : ↑n + 1 = 0
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
rw [← Nat.cast_succ, CharP.cast_eq_zero_iff R p] at h'
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
    (hp : p ≠ 0) : expand R p (contract p f) = f := by
  ext n
  rw [coeff_expand hp.bot_lt, coeff_contract hp]
  split_ifs with h
  · rw [Nat.div_mul_cancel h]
  · cases' n with n
    · exact absurd (dvd_zero p) h
    have := coeff_derivative f n
    rw [hf, coeff_zero, zero_eq_mul] at this
    cases' this with h'
    · rw [h']
    rename_i _ _ _ _ h'
    rw [← Nat.cast_succ, CharP.cast_eq_zero_iff R p] at h'
    

Proof state:
case neg.succ.inr
R : Type u
inst✝³ : CommSemiring R
S : Type v
inst✝² : CommSemiring S
p q : ℕ
inst✝¹ : CharP R p
inst✝ : NoZeroDivisors R
f : R[X]
hf : derivative f = 0
hp : p ≠ 0
n : ℕ
h : ¬p ∣ Nat.succ n
h' : p ∣ Nat.succ n
⊢ 0 = coeff f (Nat.succ n)

Next tactic:
exact absurd h' h
theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := by
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
⊢ map (frobenius R p) ((expand R p) f) = f ^ p

Next tactic:
refine' f.induction_on' (fun a b ha hb => _) fun n a => _
theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := by
  refine' f.induction_on' (fun a b ha hb => _) fun n a => _
  · 

Proof state:
case refine'_1
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f a b : R[X]
ha : map (frobenius R p) ((expand R p) a) = a ^ p
hb : map (frobenius R p) ((expand R p) b) = b ^ p
⊢ map (frobenius R p) ((expand R p) (a + b)) = (a + b) ^ p

Next tactic:
rw [AlgHom.map_add, Polynomial.map_add, ha, hb, add_pow_char]
theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := by
  refine' f.induction_on' (fun a b ha hb => _) fun n a => _
  · rw [AlgHom.map_add, Polynomial.map_add, ha, hb, add_pow_char]
  · 

Proof state:
case refine'_2
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
n : ℕ
a : R
⊢ map (frobenius R p) ((expand R p) ((monomial n) a)) = (monomial n) a ^ p

Next tactic:
rw [expand_monomial, map_monomial, ← C_mul_X_pow_eq_monomial, ← C_mul_X_pow_eq_monomial,
      mul_pow, ← C.map_pow, frobenius_def]
theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := by
  refine' f.induction_on' (fun a b ha hb => _) fun n a => _
  · rw [AlgHom.map_add, Polynomial.map_add, ha, hb, add_pow_char]
  · rw [expand_monomial, map_monomial, ← C_mul_X_pow_eq_monomial, ← C_mul_X_pow_eq_monomial,
      mul_pow, ← C.map_pow, frobenius_def]
    

Proof state:
case refine'_2
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
n : ℕ
a : R
⊢ C (a ^ p) * X ^ (n * p) = C (a ^ p) * (X ^ n) ^ p

Next tactic:
ring
theorem map_expand_pow_char (f : R[X]) (n : ℕ) :
    map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
n : ℕ
⊢ map (frobenius R p ^ n) ((expand R (p ^ n)) f) = f ^ p ^ n

Next tactic:
induction' n with _ n_ih
theorem map_expand_pow_char (f : R[X]) (n : ℕ) :
    map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by
  induction' n with _ n_ih
  · 

Proof state:
case zero
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
⊢ map (frobenius R p ^ Nat.zero) ((expand R (p ^ Nat.zero)) f) = f ^ p ^ Nat.zero

Next tactic:
simp [RingHom.one_def]
theorem map_expand_pow_char (f : R[X]) (n : ℕ) :
    map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by
  induction' n with _ n_ih
  · simp [RingHom.one_def]
  

Proof state:
case succ
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
n✝ : ℕ
n_ih : map (frobenius R p ^ n✝) ((expand R (p ^ n✝)) f) = f ^ p ^ n✝
⊢ map (frobenius R p ^ Nat.succ n✝) ((expand R (p ^ Nat.succ n✝)) f) = f ^ p ^ Nat.succ n✝

Next tactic:
symm
theorem map_expand_pow_char (f : R[X]) (n : ℕ) :
    map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by
  induction' n with _ n_ih
  · simp [RingHom.one_def]
  symm
  

Proof state:
case succ
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : CommSemiring S
p q : ℕ
inst✝ : CharP R p
hp : Fact (Nat.Prime p)
f : R[X]
n✝ : ℕ
n_ih : map (frobenius R p ^ n✝) ((expand R (p ^ n✝)) f) = f ^ p ^ n✝
⊢ f ^ p ^ Nat.succ n✝ = map (frobenius R p ^ Nat.succ n✝) ((expand R (p ^ Nat.succ n✝)) f)

Next tactic:
rw [pow_succ', pow_mul, ← n_ih, ← expand_char, pow_succ, RingHom.mul_def, ← map_map, mul_comm,
    expand_mul, ← map_expand]
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
⊢ IsLocalRingHom ↑(expand R p)

Next tactic:
refine' ⟨fun f hf1 => _⟩
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; 

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit (↑(expand R p) f)
⊢ IsUnit f

Next tactic:
norm_cast at hf1
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
  

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit ((expand R p) f)
⊢ IsUnit f

Next tactic:
have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
  have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
  

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit ((expand R p) f)
hf2 : (expand R p) f = C (coeff ((expand R p) f) 0)
⊢ IsUnit f

Next tactic:
rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
  have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
  rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2
  

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit ((expand R p) f)
hf2 : (expand R p) f = C (coeff f 0)
⊢ IsUnit f

Next tactic:
rw [hf2, isUnit_C] at hf1
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
  have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
  rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2
  rw [hf2, isUnit_C] at hf1; 

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit (coeff f 0)
hf2 : (expand R p) f = C (coeff f 0)
⊢ IsUnit f

Next tactic:
rw [expand_eq_C hp] at hf2
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
    IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
  refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
  have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
  rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2
  rw [hf2, isUnit_C] at hf1; rw [expand_eq_C hp] at hf2; 

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : 0 < p
f : R[X]
hf1 : IsUnit (coeff f 0)
hf2 : f = C (coeff f 0)
⊢ IsUnit f

Next tactic:
rwa [hf2, isUnit_C]
theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} :
    Irreducible (expand R (p ^ n) f) → Irreducible f :=
  Nat.recOn n (fun hf => by 

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : p ≠ 0
f : R[X]
n : ℕ
hf : Irreducible ((expand R (p ^ Nat.zero)) f)
⊢ Irreducible f

Next tactic:
rwa [pow_zero, expand_one] at hf
theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} :
    Irreducible (expand R (p ^ n) f) → Irreducible f :=
  Nat.recOn n (fun hf => by rwa [pow_zero, expand_one] at hf) fun n ih hf =>
    ih <| of_irreducible_expand hp <| by
      

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : p ≠ 0
f : R[X]
n✝ n : ℕ
ih : Irreducible ((expand R (p ^ n)) f) → Irreducible f
hf : Irreducible ((expand R (p ^ Nat.succ n)) f)
⊢ Irreducible ((expand R p) ((expand R (p ^ n)) f))

Next tactic:
rw [pow_succ] at hf
theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} :
    Irreducible (expand R (p ^ n) f) → Irreducible f :=
  Nat.recOn n (fun hf => by rwa [pow_zero, expand_one] at hf) fun n ih hf =>
    ih <| of_irreducible_expand hp <| by
      rw [pow_succ] at hf
      

Proof state:
R : Type u
inst✝¹ : CommRing R
inst✝ : IsDomain R
p : ℕ
hp : p ≠ 0
f : R[X]
n✝ n : ℕ
ih : Irreducible ((expand R (p ^ n)) f) → Irreducible f
hf : Irreducible ((expand R (p * p ^ n)) f)
⊢ Irreducible ((expand R p) ((expand R (p ^ n)) f))

Next tactic:
rwa [expand_expand]
instance : ConcreteCategory.{v} (AlgebraCat.{v} R) where
  forget :=
    { obj := fun R => R
      map := fun f => f.toFun }
  forget_faithful := ⟨fun h => AlgHom.ext (by 

Proof state:
R : Type u
inst✝ : CommRing R
X✝ Y✝ : AlgebraCat R
a₁✝ a₂✝ : X✝ ⟶ Y✝
h :
  (CategoryTheory.Functor.mk { obj := fun R_1 => ↑R_1, map := fun {X Y} f => f.toFun }).map a₁✝ =
    (CategoryTheory.Functor.mk { obj := fun R_1 => ↑R_1, map := fun {X Y} f => f.toFun }).map a₂✝
⊢ ∀ (x : ↑X✝), a₁✝ x = a₂✝ x

Next tactic:
intros x
instance : ConcreteCategory.{v} (AlgebraCat.{v} R) where
  forget :=
    { obj := fun R => R
      map := fun f => f.toFun }
  forget_faithful := ⟨fun h => AlgHom.ext (by intros x; 

Proof state:
R : Type u
inst✝ : CommRing R
X✝ Y✝ : AlgebraCat R
a₁✝ a₂✝ : X✝ ⟶ Y✝
h :
  (CategoryTheory.Functor.mk { obj := fun R_1 => ↑R_1, map := fun {X Y} f => f.toFun }).map a₁✝ =
    (CategoryTheory.Functor.mk { obj := fun R_1 => ↑R_1, map := fun {X Y} f => f.toFun }).map a₂✝
x : ↑X✝
⊢ a₁✝ x = a₂✝ x

Next tactic:
dsimp at h
instance : ConcreteCategory.{v} (AlgebraCat.{v} R) where
  forget :=
    { obj := fun R => R
      map := fun f => f.toFun }
  forget_faithful := ⟨fun h => AlgHom.ext (by intros x; dsimp at h; 

Proof state:
R : Type u
inst✝ : CommRing R
X✝ Y✝ : AlgebraCat R
a₁✝ a₂✝ : X✝ ⟶ Y✝
h : ⇑a₁✝ = ⇑a₂✝
x : ↑X✝
⊢ a₁✝ x = a₂✝ x

Next tactic:
rw [h]
/-- The "free algebra" functor, sending a type `S` to the free algebra on `S`. -/
@[simps!]
def free : Type u ⥤ AlgebraCat.{u} R where
  obj S :=
    { carrier := FreeAlgebra R S
      isRing := Algebra.semiringToRing R }
  map f := FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f
  -- porting note: `apply FreeAlgebra.hom_ext` was `ext1`.
  map_id := by 

Proof state:
R : Type u
inst✝ : CommRing R
M N U : ModuleCat R
⊢ ∀ (X : Type u),
    { obj := fun S => mk (FreeAlgebra R S), map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.map
        (𝟙 X) =
      𝟙
        ({ obj := fun S => mk (FreeAlgebra R S), map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.obj
          X)

Next tactic:
intro X
/-- The "free algebra" functor, sending a type `S` to the free algebra on `S`. -/
@[simps!]
def free : Type u ⥤ AlgebraCat.{u} R where
  obj S :=
    { carrier := FreeAlgebra R S
      isRing := Algebra.semiringToRing R }
  map f := FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f
  -- porting note: `apply FreeAlgebra.hom_ext` was `ext1`.
  map_id := by intro X; 

Proof state:
R : Type u
inst✝ : CommRing R
M N U : ModuleCat R
X : Type u
⊢ { obj := fun S => mk (FreeAlgebra R S), map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.map (𝟙 X) =
    𝟙 ({ obj := fun S => mk (FreeAlgebra R S), map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.obj X)

Next tactic:
apply FreeAlgebra.hom_ext
/-- The "free algebra" functor, sending a type `S` to the free algebra on `S`. -/
@[simps!]
def free : Type u ⥤ AlgebraCat.{u} R where
  obj S :=
    { carrier := FreeAlgebra R S
      isRing := Algebra.semiringToRing R }
  map f := FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f
  -- porting note: `apply FreeAlgebra.hom_ext` was `ext1`.
  map_id := by intro X; apply FreeAlgebra.hom_ext; 

Proof state:
case w
R : Type u
inst✝ : CommRing R
M N U : ModuleCat R
X : Type u
⊢ ⇑({ obj := fun S => mk (FreeAlgebra R S), map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.map
          (𝟙 X)) ∘
      FreeAlgebra.ι R =
    ⇑(𝟙
          ({ obj := fun S => mk (FreeAlgebra R S),
                map := fun {X Y} f => (FreeAlgebra.lift R) (FreeAlgebra.ι R ∘ f) }.obj
            X)) ∘
      FreeAlgebra.ι R

Next tactic:
simp only [FreeAlgebra.ι_comp_lift]
/-- The "free algebra" functor, sending a type `S` to the free algebra on `S`. -/
@[simps!]
def free : Type u ⥤ AlgebraCat.{u} R where
  obj S :=
    { carrier := FreeAlgebra R S
      isRing := Algebra.semiringToRing R }
  map f := FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f
  -- porting note: `apply FreeAlgebra.hom_ext` was `ext1`.
  map_id := by intro X; apply FreeAlgebra.hom_ext; simp only [FreeAlgebra.ι_comp_lift]; 

Proof state:
case w
R : Type u
inst✝ : CommRing R
M N U : ModuleCat R
X : Type u
⊢ FreeAlgebra.ι R ∘ 𝟙 X = ⇑(𝟙 (mk (FreeAlgebra R X))) ∘ FreeAlgebra.ι R

Next tactic:
rfl