l3lab/ntp-mathlib huggingface dataset:
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; 

Proof state:
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp✝ : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
hp : p = 0
⊢ erase (natDegree p) p = 0

Next tactic:
rw [hp]
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; 

Proof state:
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp✝ : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
hp : p = 0
⊢ erase (natDegree 0) 0 = 0

Next tactic:
simp only [natDegree_zero, erase_zero]
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  

Proof state:
case neg.intro
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
⊢ ∃ q, map f q = p ∧ degree q = degree p ∧ Monic q

Next tactic:
have hdeg : q.degree < (X ^ p.natDegree).degree := by
    rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
    exact degree_erase_lt p_neq_0
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  have hdeg : q.degree < (X ^ p.natDegree).degree := by
    

Proof state:
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
⊢ degree q < degree (X ^ natDegree p)

Next tactic:
rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  have hdeg : q.degree < (X ^ p.natDegree).degree := by
    rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
    

Proof state:
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
⊢ degree (erase (natDegree p) p) < degree p

Next tactic:
exact degree_erase_lt p_neq_0
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  have hdeg : q.degree < (X ^ p.natDegree).degree := by
    rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
    exact degree_erase_lt p_neq_0
  

Proof state:
case neg.intro
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
hdeg : degree q < degree (X ^ natDegree p)
⊢ ∃ q, map f q = p ∧ degree q = degree p ∧ Monic q

Next tactic:
refine' ⟨q + X ^ p.natDegree, _, _, (monic_X_pow _).add_of_right hdeg⟩
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  have hdeg : q.degree < (X ^ p.natDegree).degree := by
    rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
    exact degree_erase_lt p_neq_0
  refine' ⟨q + X ^ p.natDegree, _, _, (monic_X_pow _).add_of_right hdeg⟩
  · 

Proof state:
case neg.intro.refine'_1
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
hdeg : degree q < degree (X ^ natDegree p)
⊢ map f (q + X ^ natDegree p) = p

Next tactic:
rw [Polynomial.map_add, hq.1, Polynomial.map_pow, map_X, H]
/-- A monic polynomial lifts if and only if it can be lifted to a monic polynomial
of the same degree. -/
theorem lifts_and_degree_eq_and_monic [Nontrivial S] {p : S[X]} (hlifts : p ∈ lifts f)
    (hp : p.Monic) : ∃ q : R[X], map f q = p ∧ q.degree = p.degree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial R with hR hR
  · obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq hlifts
    exact ⟨q, hq.1, hq.2, monic_of_subsingleton _⟩
  have H : erase p.natDegree p + X ^ p.natDegree = p := by
    simpa only [hp.leadingCoeff, C_1, one_mul, eraseLead] using eraseLead_add_C_mul_X_pow p
  by_cases h0 : erase p.natDegree p = 0
  · rw [← H, h0, zero_add]
    refine' ⟨X ^ p.natDegree, _, _, monic_X_pow p.natDegree⟩
    · rw [Polynomial.map_pow, map_X]
    · rw [degree_X_pow, degree_X_pow]
  obtain ⟨q, hq⟩ := mem_lifts_and_degree_eq (erase_mem_lifts p.natDegree hlifts)
  have p_neq_0 : p ≠ 0 := by intro hp; apply h0; rw [hp]; simp only [natDegree_zero, erase_zero]
  have hdeg : q.degree < (X ^ p.natDegree).degree := by
    rw [@degree_X_pow R, hq.2, ← degree_eq_natDegree p_neq_0]
    exact degree_erase_lt p_neq_0
  refine' ⟨q + X ^ p.natDegree, _, _, (monic_X_pow _).add_of_right hdeg⟩
  · rw [Polynomial.map_add, hq.1, Polynomial.map_pow, map_X, H]
  · 

Proof state:
case neg.intro.refine'_2
R : Type u
inst✝² : Semiring R
S : Type v
inst✝¹ : Semiring S
f : R →+* S
inst✝ : Nontrivial S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial R
H : erase (natDegree p) p + X ^ natDegree p = p
h0 : ¬erase (natDegree p) p = 0
q : R[X]
hq : map f q = erase (natDegree p) p ∧ degree q = degree (erase (natDegree p) p)
p_neq_0 : p ≠ 0
hdeg : degree q < degree (X ^ natDegree p)
⊢ degree (q + X ^ natDegree p) = degree p

Next tactic:
rw [degree_add_eq_right_of_degree_lt hdeg, degree_X_pow, degree_eq_natDegree hp.ne_zero]
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  

Proof state:
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
⊢ ∃ q, map f q = p ∧ natDegree q = natDegree p ∧ Monic q

Next tactic:
cases' subsingleton_or_nontrivial S with hR hR
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · 

Proof state:
case inl
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Subsingleton S
⊢ ∃ q, map f q = p ∧ natDegree q = natDegree p ∧ Monic q

Next tactic:
obtain rfl : p = 1 := Subsingleton.elim _ _
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · obtain rfl : p = 1 := Subsingleton.elim _ _
    

Proof state:
case inl
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
hR : Subsingleton S
hlifts : 1 ∈ lifts f
hp : Monic 1
⊢ ∃ q, map f q = 1 ∧ natDegree q = natDegree 1 ∧ Monic q

Next tactic:
refine' ⟨1, Subsingleton.elim _ _, by simp, by simp⟩
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · obtain rfl : p = 1 := Subsingleton.elim _ _
    refine' ⟨1, Subsingleton.elim _ _, by 

Proof state:
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
hR : Subsingleton S
hlifts : 1 ∈ lifts f
hp : Monic 1
⊢ natDegree 1 = natDegree 1

Next tactic:
simp
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · obtain rfl : p = 1 := Subsingleton.elim _ _
    refine' ⟨1, Subsingleton.elim _ _, by simp, by 

Proof state:
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
hR : Subsingleton S
hlifts : 1 ∈ lifts f
hp : Monic 1
⊢ Monic 1

Next tactic:
simp
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · obtain rfl : p = 1 := Subsingleton.elim _ _
    refine' ⟨1, Subsingleton.elim _ _, by simp, by simp⟩
  

Proof state:
case inr
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial S
⊢ ∃ q, map f q = p ∧ natDegree q = natDegree p ∧ Monic q

Next tactic:
obtain ⟨p', h₁, h₂, h₃⟩ := lifts_and_degree_eq_and_monic hlifts hp
theorem lifts_and_natDegree_eq_and_monic {p : S[X]} (hlifts : p ∈ lifts f) (hp : p.Monic) :
    ∃ q : R[X], map f q = p ∧ q.natDegree = p.natDegree ∧ q.Monic := by
  cases' subsingleton_or_nontrivial S with hR hR
  · obtain rfl : p = 1 := Subsingleton.elim _ _
    refine' ⟨1, Subsingleton.elim _ _, by simp, by simp⟩
  obtain ⟨p', h₁, h₂, h₃⟩ := lifts_and_degree_eq_and_monic hlifts hp
  

Proof state:
case inr.intro.intro.intro
R : Type u
inst✝¹ : Semiring R
S : Type v
inst✝ : Semiring S
f : R →+* S
p : S[X]
hlifts : p ∈ lifts f
hp : Monic p
hR : Nontrivial S
p' : R[X]
h₁ : map f p' = p
h₂ : degree p' = degree p
h₃ : Monic p'
⊢ ∃ q, map f q = p ∧ natDegree q = natDegree p ∧ Monic q

Next tactic:
exact ⟨p', h₁, natDegree_eq_of_degree_eq h₂, h₃⟩
/-- If `R` and `S` are rings, `p` is in the subring of polynomials that lift if and only if it is in
the subsemiring of polynomials that lift. -/
theorem lifts_iff_liftsRing (p : S[X]) : p ∈ lifts f ↔ p ∈ liftsRing f := by
  

Proof state:
R : Type u
inst✝¹ : Ring R
S : Type v
inst✝ : Ring S
f : R →+* S
p : S[X]
⊢ p ∈ lifts f ↔ p ∈ liftsRing f

Next tactic:
simp only [lifts, liftsRing, RingHom.mem_range, RingHom.mem_rangeS]
/-- `mapAlg` is the morphism induced by `R → S`. -/
theorem mapAlg_eq_map (p : R[X]) : mapAlg R S p = map (algebraMap R S) p := by
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : R[X]
⊢ (mapAlg R S) p = map (algebraMap R S) p

Next tactic:
simp only [mapAlg, aeval_def, eval₂_eq_sum, map, algebraMap_apply, RingHom.coe_comp]
/-- `mapAlg` is the morphism induced by `R → S`. -/
theorem mapAlg_eq_map (p : R[X]) : mapAlg R S p = map (algebraMap R S) p := by
  simp only [mapAlg, aeval_def, eval₂_eq_sum, map, algebraMap_apply, RingHom.coe_comp]
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : R[X]
⊢ (sum p fun e a => C ((algebraMap R S) a) * X ^ e) = sum p fun e a => (⇑C ∘ ⇑(algebraMap R S)) a * X ^ e

Next tactic:
ext
/-- `mapAlg` is the morphism induced by `R → S`. -/
theorem mapAlg_eq_map (p : R[X]) : mapAlg R S p = map (algebraMap R S) p := by
  simp only [mapAlg, aeval_def, eval₂_eq_sum, map, algebraMap_apply, RingHom.coe_comp]
  ext; 

Proof state:
case a
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : R[X]
n✝ : ℕ
⊢ coeff (sum p fun e a => C ((algebraMap R S) a) * X ^ e) n✝ =
    coeff (sum p fun e a => (⇑C ∘ ⇑(algebraMap R S)) a * X ^ e) n✝

Next tactic:
congr
/-- A polynomial `p` lifts if and only if it is in the image of `mapAlg`. -/
theorem mem_lifts_iff_mem_alg (R : Type u) [CommSemiring R] {S : Type v} [Semiring S] [Algebra R S]
    (p : S[X]) : p ∈ lifts (algebraMap R S) ↔ p ∈ AlgHom.range (@mapAlg R _ S _ _) := by
  

Proof state:
R✝ : Type u
inst✝⁵ : CommSemiring R✝
S✝ : Type v
inst✝⁴ : Semiring S✝
inst✝³ : Algebra R✝ S✝
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : S[X]
⊢ p ∈ lifts (algebraMap R S) ↔ p ∈ AlgHom.range (mapAlg R S)

Next tactic:
simp only [coe_mapRingHom, lifts, mapAlg_eq_map, AlgHom.mem_range, RingHom.mem_rangeS]
/-- If `p` lifts and `(r : R)` then `r • p` lifts. -/
theorem smul_mem_lifts {p : S[X]} (r : R) (hp : p ∈ lifts (algebraMap R S)) :
    r • p ∈ lifts (algebraMap R S) := by
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : S[X]
r : R
hp : p ∈ lifts (algebraMap R S)
⊢ r • p ∈ lifts (algebraMap R S)

Next tactic:
rw [mem_lifts_iff_mem_alg] at hp ⊢
/-- If `p` lifts and `(r : R)` then `r • p` lifts. -/
theorem smul_mem_lifts {p : S[X]} (r : R) (hp : p ∈ lifts (algebraMap R S)) :
    r • p ∈ lifts (algebraMap R S) := by
  rw [mem_lifts_iff_mem_alg] at hp ⊢
  

Proof state:
R : Type u
inst✝² : CommSemiring R
S : Type v
inst✝¹ : Semiring S
inst✝ : Algebra R S
p : S[X]
r : R
hp : p ∈ AlgHom.range (mapAlg R S)
⊢ r • p ∈ AlgHom.range (mapAlg R S)

Next tactic:
exact Subalgebra.smul_mem (mapAlg R S).range hp r
theorem lhopital_zero_right_on_Ioo (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x)
    (hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x) (hg' : ∀ x ∈ Ioo a b, g' x ≠ 0)
    (hfa : Tendsto f (𝓝[>] a) (𝓝 0)) (hga : Tendsto g (𝓝[>] a) (𝓝 0))
    (hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l) :
    Tendsto (fun x => f x / g x) (𝓝[>] a) l := by
  

Proof state:
a b : ℝ
hab : a < b
l : Filter ℝ
f f' g g' : ℝ → ℝ
hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x
hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x
hg' : ∀ x ∈ Ioo a b, g' x ≠ 0
hfa : Tendsto f (𝓝[>] a) (𝓝 0)
hga : Tendsto g (𝓝[>] a) (𝓝 0)
hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l
⊢ Tendsto (fun x => f x / g x) (𝓝[>] a) l

Next tactic:
have sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b := fun x hx =>
    Ioo_subset_Ioo (le_refl a) (le_of_lt hx.2)
theorem lhopital_zero_right_on_Ioo (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x)
    (hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x) (hg' : ∀ x ∈ Ioo a b, g' x ≠ 0)
    (hfa : Tendsto f (𝓝[>] a) (𝓝 0)) (hga : Tendsto g (𝓝[>] a) (𝓝 0))
    (hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l) :
    Tendsto (fun x => f x / g x) (𝓝[>] a) l := by
  have sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b := fun x hx =>
    Ioo_subset_Ioo (le_refl a) (le_of_lt hx.2)
  

Proof state:
a b : ℝ
hab : a < b
l : Filter ℝ
f f' g g' : ℝ → ℝ
hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x
hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x
hg' : ∀ x ∈ Ioo a b, g' x ≠ 0
hfa : Tendsto f (𝓝[>] a) (𝓝 0)
hga : Tendsto g (𝓝[>] a) (𝓝 0)
hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l
sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b
⊢ Tendsto (fun x => f x / g x) (𝓝[>] a) l

Next tactic:
have hg : ∀ x ∈ Ioo a b, g x ≠ 0 := by
    intro x hx h
    have : Tendsto g (𝓝[<] x) (𝓝 0) := by
      rw [← h, ← nhdsWithin_Ioo_eq_nhdsWithin_Iio hx.1]
      exact ((hgg' x hx).continuousAt.continuousWithinAt.mono <| sub x hx).tendsto
    obtain ⟨y, hyx, hy⟩ : ∃ c ∈ Ioo a x, g' c = 0
    exact exists_hasDerivAt_eq_zero' hx.1 hga this fun y hy => hgg' y <| sub x hx hy
    exact hg' y (sub x hx hyx) hy
theorem lhopital_zero_right_on_Ioo (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x)
    (hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x) (hg' : ∀ x ∈ Ioo a b, g' x ≠ 0)
    (hfa : Tendsto f (𝓝[>] a) (𝓝 0)) (hga : Tendsto g (𝓝[>] a) (𝓝 0))
    (hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l) :
    Tendsto (fun x => f x / g x) (𝓝[>] a) l := by
  have sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b := fun x hx =>
    Ioo_subset_Ioo (le_refl a) (le_of_lt hx.2)
  have hg : ∀ x ∈ Ioo a b, g x ≠ 0 := by
    

Proof state:
a b : ℝ
hab : a < b
l : Filter ℝ
f f' g g' : ℝ → ℝ
hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x
hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x
hg' : ∀ x ∈ Ioo a b, g' x ≠ 0
hfa : Tendsto f (𝓝[>] a) (𝓝 0)
hga : Tendsto g (𝓝[>] a) (𝓝 0)
hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l
sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b
⊢ ∀ x ∈ Ioo a b, g x ≠ 0

Next tactic:
intro x hx h
theorem lhopital_zero_right_on_Ioo (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x)
    (hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x) (hg' : ∀ x ∈ Ioo a b, g' x ≠ 0)
    (hfa : Tendsto f (𝓝[>] a) (𝓝 0)) (hga : Tendsto g (𝓝[>] a) (𝓝 0))
    (hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l) :
    Tendsto (fun x => f x / g x) (𝓝[>] a) l := by
  have sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b := fun x hx =>
    Ioo_subset_Ioo (le_refl a) (le_of_lt hx.2)
  have hg : ∀ x ∈ Ioo a b, g x ≠ 0 := by
    intro x hx h
    

Proof state:
a b : ℝ
hab : a < b
l : Filter ℝ
f f' g g' : ℝ → ℝ
hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x
hgg' : ∀ x ∈ Ioo a b, HasDerivAt g (g' x) x
hg' : ∀ x ∈ Ioo a b, g' x ≠ 0
hfa : Tendsto f (𝓝[>] a) (𝓝 0)
hga : Tendsto g (𝓝[>] a) (𝓝 0)
hdiv : Tendsto (fun x => f' x / g' x) (𝓝[>] a) l
sub : ∀ x ∈ Ioo a b, Ioo a x ⊆ Ioo a b
x : ℝ
hx : x ∈ Ioo a b
h : g x = 0
⊢ False

Next tactic:
have : Tendsto g (𝓝[<] x) (𝓝 0) := by
      rw [← h, ← nhdsWithin_Ioo_eq_nhdsWithin_Iio hx.1]
      exact ((hgg' x hx).continuousAt.continuousWithinAt.mono <| sub x hx).tendsto