l3lab/ntp-mathlib huggingface dataset:
theorem normSq_exp (q : ℍ[ℝ]) : normSq (exp ℝ q) = exp ℝ q.re ^ 2 :=
  calc
    normSq (exp ℝ q) =
        normSq (exp ℝ q.re • (↑(Real.cos ‖q.im‖) + (Real.sin ‖q.im‖ / ‖q.im‖) • q.im)) :=
      by rw [exp_eq]
    _ = exp ℝ q.re ^ 2 * normSq (↑(Real.cos ‖q.im‖) + (Real.sin ‖q.im‖ / ‖q.im‖) • q.im) := by
      rw [normSq_smul]
    _ = exp ℝ q.re ^ 2 * (Real.cos ‖q.im‖ ^ 2 + Real.sin ‖q.im‖ ^ 2) := by
      congr 1
      obtain hv | hv := eq_or_ne ‖q.im‖ 0
      · simp [hv]
      rw [normSq_add, normSq_smul, star_smul, coe_mul_eq_smul, smul_re, smul_re, star_re, im_re,
        smul_zero, smul_zero, mul_zero, add_zero, div_pow, normSq_coe,
        normSq_eq_norm_mul_self, ← sq, div_mul_cancel _ (pow_ne_zero _ hv)]
    _ = exp ℝ q.re ^ 2 := by 

Proof state:
q : ℍ
⊢ exp ℝ q.re ^ 2 * (Real.cos ‖im q‖ ^ 2 + Real.sin ‖im q‖ ^ 2) = exp ℝ q.re ^ 2

Next tactic:
rw [Real.cos_sq_add_sin_sq, mul_one]
/-- Note that this implies that exponentials of pure imaginary quaternions are unit quaternions
since in that case the RHS is `1` via `exp_zero` and `norm_one`. -/
@[simp]
theorem norm_exp (q : ℍ[ℝ]) : ‖exp ℝ q‖ = ‖exp ℝ q.re‖ := by
  

Proof state:
q : ℍ
⊢ ‖exp ℝ q‖ = ‖exp ℝ q.re‖

Next tactic:
rw [norm_eq_sqrt_real_inner (exp ℝ q), inner_self, normSq_exp, Real.sqrt_sq_eq_abs,
    Real.norm_eq_abs]
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀
h : Commute a b
⊢ inverse (a * b) = inverse b * inverse a

Next tactic:
by_cases hab : IsUnit (a * b)
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  by_cases hab : IsUnit (a * b)
  · 

Proof state:
case pos
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀
h : Commute a b
hab : IsUnit (a * b)
⊢ inverse (a * b) = inverse b * inverse a

Next tactic:
obtain ⟨⟨a, rfl⟩, b, rfl⟩ := h.isUnit_mul_iff.mp hab
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  by_cases hab : IsUnit (a * b)
  · obtain ⟨⟨a, rfl⟩, b, rfl⟩ := h.isUnit_mul_iff.mp hab
    

Proof state:
case pos.intro.intro.intro
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀ˣ
h : Commute ↑a ↑b
hab : IsUnit (↑a * ↑b)
⊢ inverse (↑a * ↑b) = inverse ↑b * inverse ↑a

Next tactic:
rw [← Units.val_mul, inverse_unit, inverse_unit, inverse_unit, ← Units.val_mul, mul_inv_rev]
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  by_cases hab : IsUnit (a * b)
  · obtain ⟨⟨a, rfl⟩, b, rfl⟩ := h.isUnit_mul_iff.mp hab
    rw [← Units.val_mul, inverse_unit, inverse_unit, inverse_unit, ← Units.val_mul, mul_inv_rev]
  

Proof state:
case neg
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀
h : Commute a b
hab : ¬IsUnit (a * b)
⊢ inverse (a * b) = inverse b * inverse a

Next tactic:
obtain ha | hb := not_and_or.mp (mt h.isUnit_mul_iff.mpr hab)
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  by_cases hab : IsUnit (a * b)
  · obtain ⟨⟨a, rfl⟩, b, rfl⟩ := h.isUnit_mul_iff.mp hab
    rw [← Units.val_mul, inverse_unit, inverse_unit, inverse_unit, ← Units.val_mul, mul_inv_rev]
  obtain ha | hb := not_and_or.mp (mt h.isUnit_mul_iff.mpr hab)
  · 

Proof state:
case neg.inl
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀
h : Commute a b
hab : ¬IsUnit (a * b)
ha : ¬IsUnit a
⊢ inverse (a * b) = inverse b * inverse a

Next tactic:
rw [inverse_non_unit _ hab, inverse_non_unit _ ha, mul_zero]
theorem mul_inverse_rev' {a b : M₀} (h : Commute a b) :
    inverse (a * b) = inverse b * inverse a := by
  by_cases hab : IsUnit (a * b)
  · obtain ⟨⟨a, rfl⟩, b, rfl⟩ := h.isUnit_mul_iff.mp hab
    rw [← Units.val_mul, inverse_unit, inverse_unit, inverse_unit, ← Units.val_mul, mul_inv_rev]
  obtain ha | hb := not_and_or.mp (mt h.isUnit_mul_iff.mpr hab)
  · rw [inverse_non_unit _ hab, inverse_non_unit _ ha, mul_zero]
  · 

Proof state:
case neg.inr
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a b : M₀
h : Commute a b
hab : ¬IsUnit (a * b)
hb : ¬IsUnit b
⊢ inverse (a * b) = inverse b * inverse a

Next tactic:
rw [inverse_non_unit _ hab, inverse_non_unit _ hb, zero_mul]
@[simp]
theorem div_left (hac : Commute a c) (hbc : Commute b c) : Commute (a / b) c := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
hac : Commute a c
hbc : Commute b c
⊢ Commute (a / b) c

Next tactic:
rw [div_eq_mul_inv]
@[simp]
theorem div_left (hac : Commute a c) (hbc : Commute b c) : Commute (a / b) c := by
  rw [div_eq_mul_inv]
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
hac : Commute a c
hbc : Commute b c
⊢ Commute (a * b⁻¹) c

Next tactic:
exact hac.mul_left hbc.inv_left₀
/-- The Taylor expansion of a polynomial `f` at `r`. -/
def taylor (r : R) : R[X] →ₗ[R] R[X] where
  toFun f := f.comp (X + C r)
  map_add' f g := add_comp
  map_smul' c f := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
r✝ : R
f✝ : R[X]
r c : R
f : R[X]
⊢ AddHom.toFun
      { toFun := fun f => comp f (X + C r),
        map_add' := (_ : ∀ (f g : R[X]), comp (f + g) (X + C r) = comp f (X + C r) + comp g (X + C r)) }
      (c • f) =
    (RingHom.id R) c •
      AddHom.toFun
        { toFun := fun f => comp f (X + C r),
          map_add' := (_ : ∀ (f g : R[X]), comp (f + g) (X + C r) = comp f (X + C r) + comp g (X + C r)) }
        f

Next tactic:
simp only [smul_eq_C_mul, C_mul_comp, RingHom.id_apply]
@[simp]
theorem taylor_X : taylor r X = X + C r := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
⊢ (taylor r) X = X + C r

Next tactic:
simp only [taylor_apply, X_comp]
@[simp]
theorem taylor_C (x : R) : taylor r (C x) = C x := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
x : R
⊢ (taylor r) (C x) = C x

Next tactic:
simp only [taylor_apply, C_comp]
@[simp]
theorem taylor_zero' : taylor (0 : R) = LinearMap.id := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
⊢ taylor 0 = LinearMap.id

Next tactic:
ext
@[simp]
theorem taylor_zero' : taylor (0 : R) = LinearMap.id := by
  ext
  

Proof state:
case h.h.a
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
n✝¹ n✝ : ℕ
⊢ coeff ((taylor 0 ∘ₗ monomial n✝¹) 1) n✝ = coeff ((LinearMap.id ∘ₗ monomial n✝¹) 1) n✝

Next tactic:
simp only [taylor_apply, add_zero, comp_X, _root_.map_zero, LinearMap.id_comp,
    Function.comp_apply, LinearMap.coe_comp]
theorem taylor_zero (f : R[X]) : taylor 0 f = f := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f✝ f : R[X]
⊢ (taylor 0) f = f

Next tactic:
rw [taylor_zero', LinearMap.id_apply]
@[simp]
theorem taylor_one : taylor r (1 : R[X]) = C 1 := by 

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
⊢ (taylor r) 1 = C 1

Next tactic:
rw [← C_1, taylor_C]
@[simp]
theorem taylor_monomial (i : ℕ) (k : R) : taylor r (monomial i k) = C k * (X + C r) ^ i := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
i : ℕ
k : R
⊢ (taylor r) ((monomial i) k) = C k * (X + C r) ^ i

Next tactic:
simp [taylor_apply]
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
n : ℕ
⊢ (lcoeff R n ∘ₗ taylor r) f = (leval r ∘ₗ hasseDeriv n) f

Next tactic:
congr 1
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; 

Proof state:
case e_a
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
n : ℕ
⊢ lcoeff R n ∘ₗ taylor r = leval r ∘ₗ hasseDeriv n

Next tactic:
clear! f
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; 

Proof state:
case e_a
R : Type u_1
inst✝ : Semiring R
r : R
n : ℕ
⊢ lcoeff R n ∘ₗ taylor r = leval r ∘ₗ hasseDeriv n

Next tactic:
ext i
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    

Proof state:
case e_a.h.h
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
⊢ ((lcoeff R n ∘ₗ taylor r) ∘ₗ monomial i) 1 = ((leval r ∘ₗ hasseDeriv n) ∘ₗ monomial i) 1

Next tactic:
simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
    

Proof state:
case e_a.h.h
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
⊢ (Finset.sum (Finset.range (i + 1)) fun x => (lcoeff R n) (X ^ x * C r ^ (i - x) * ↑(Nat.choose i x))) =
    ↑(Nat.choose i n) * r ^ (i - n)

Next tactic:
simp only [lcoeff_apply, ← C_eq_nat_cast, mul_assoc, ← C_pow, ← C_mul, coeff_mul_C,
      (Nat.cast_commute _ _).eq, coeff_X_pow, boole_mul, Finset.sum_ite_eq, Finset.mem_range]
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
    simp only [lcoeff_apply, ← C_eq_nat_cast, mul_assoc, ← C_pow, ← C_mul, coeff_mul_C,
      (Nat.cast_commute _ _).eq, coeff_X_pow, boole_mul, Finset.sum_ite_eq, Finset.mem_range]
    

Proof state:
case e_a.h.h
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
⊢ (if n < i + 1 then r ^ (i - n) * ↑(Nat.choose i n) else 0) = r ^ (i - n) * ↑(Nat.choose i n)

Next tactic:
split_ifs with h
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
    simp only [lcoeff_apply, ← C_eq_nat_cast, mul_assoc, ← C_pow, ← C_mul, coeff_mul_C,
      (Nat.cast_commute _ _).eq, coeff_X_pow, boole_mul, Finset.sum_ite_eq, Finset.mem_range]
    split_ifs with h; · 

Proof state:
case pos
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
h : n < i + 1
⊢ r ^ (i - n) * ↑(Nat.choose i n) = r ^ (i - n) * ↑(Nat.choose i n)

Next tactic:
rfl
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
    simp only [lcoeff_apply, ← C_eq_nat_cast, mul_assoc, ← C_pow, ← C_mul, coeff_mul_C,
      (Nat.cast_commute _ _).eq, coeff_X_pow, boole_mul, Finset.sum_ite_eq, Finset.mem_range]
    split_ifs with h; · rfl
    

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
h : ¬n < i + 1
⊢ 0 = r ^ (i - n) * ↑(Nat.choose i n)

Next tactic:
push_neg at h
/-- The `k`th coefficient of `Polynomial.taylor r f` is `(Polynomial.hasseDeriv k f).eval r`. -/
theorem taylor_coeff (n : ℕ) : (taylor r f).coeff n = (hasseDeriv n f).eval r :=
  show (lcoeff R n).comp (taylor r) f = (leval r).comp (hasseDeriv n) f by
    congr 1; clear! f; ext i
    simp only [leval_apply, mul_one, one_mul, eval_monomial, LinearMap.comp_apply, coeff_C_mul,
      hasseDeriv_monomial, taylor_apply, monomial_comp, C_1, (commute_X (C r)).add_pow i,
      map_sum]
    simp only [lcoeff_apply, ← C_eq_nat_cast, mul_assoc, ← C_pow, ← C_mul, coeff_mul_C,
      (Nat.cast_commute _ _).eq, coeff_X_pow, boole_mul, Finset.sum_ite_eq, Finset.mem_range]
    split_ifs with h; · rfl
    push_neg at h; 

Proof state:
case neg
R : Type u_1
inst✝ : Semiring R
r : R
n i : ℕ
h : i + 1 ≤ n
⊢ 0 = r ^ (i - n) * ↑(Nat.choose i n)

Next tactic:
rw [Nat.choose_eq_zero_of_lt h, Nat.cast_zero, mul_zero]
@[simp]
theorem taylor_coeff_zero : (taylor r f).coeff 0 = f.eval r := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
⊢ coeff ((taylor r) f) 0 = eval r f

Next tactic:
rw [taylor_coeff, hasseDeriv_zero, LinearMap.id_apply]
@[simp]
theorem taylor_coeff_one : (taylor r f).coeff 1 = f.derivative.eval r := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r : R
f : R[X]
⊢ coeff ((taylor r) f) 1 = eval r (derivative f)

Next tactic:
rw [taylor_coeff, hasseDeriv_one]
@[simp]
theorem natDegree_taylor (p : R[X]) (r : R) : natDegree (taylor r p) = natDegree p := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r✝ : R
f p : R[X]
r : R
⊢ natDegree ((taylor r) p) = natDegree p

Next tactic:
refine' map_natDegree_eq_natDegree _ _
@[simp]
theorem natDegree_taylor (p : R[X]) (r : R) : natDegree (taylor r p) = natDegree p := by
  refine' map_natDegree_eq_natDegree _ _
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r✝ : R
f p : R[X]
r : R
⊢ ∀ (n : ℕ) (c : R), c ≠ 0 → natDegree ((taylor r) ((monomial n) c)) = n

Next tactic:
nontriviality R
@[simp]
theorem natDegree_taylor (p : R[X]) (r : R) : natDegree (taylor r p) = natDegree p := by
  refine' map_natDegree_eq_natDegree _ _
  nontriviality R
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r✝ : R
f p : R[X]
r : R
✝ : Nontrivial R
⊢ ∀ (n : ℕ) (c : R), c ≠ 0 → natDegree ((taylor r) ((monomial n) c)) = n

Next tactic:
intro n c c0
@[simp]
theorem natDegree_taylor (p : R[X]) (r : R) : natDegree (taylor r p) = natDegree p := by
  refine' map_natDegree_eq_natDegree _ _
  nontriviality R
  intro n c c0
  

Proof state:
R : Type u_1
inst✝ : Semiring R
r✝ : R
f p : R[X]
r : R
✝ : Nontrivial R
n : ℕ
c : R
c0 : c ≠ 0
⊢ natDegree ((taylor r) ((monomial n) c)) = n

Next tactic:
simp [taylor_monomial, natDegree_C_mul_eq_of_mul_ne_zero, natDegree_pow_X_add_C, c0]
@[simp]
theorem taylor_mul {R} [CommSemiring R] (r : R) (p q : R[X]) :
    taylor r (p * q) = taylor r p * taylor r q := by 

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f : R✝[X]
R : Type u_2
inst✝ : CommSemiring R
r : R
p q : R[X]
⊢ (taylor r) (p * q) = (taylor r) p * (taylor r) q

Next tactic:
simp only [taylor_apply, mul_comp]
theorem taylor_taylor {R} [CommSemiring R] (f : R[X]) (r s : R) :
    taylor r (taylor s f) = taylor (r + s) f := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommSemiring R
f : R[X]
r s : R
⊢ (taylor r) ((taylor s) f) = (taylor (r + s)) f

Next tactic:
simp only [taylor_apply, comp_assoc, map_add, add_comp, X_comp, C_comp, C_add, add_assoc]
theorem taylor_eval {R} [CommSemiring R] (r : R) (f : R[X]) (s : R) :
    (taylor r f).eval s = f.eval (s + r) := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommSemiring R
r : R
f : R[X]
s : R
⊢ eval s ((taylor r) f) = eval (s + r) f

Next tactic:
simp only [taylor_apply, eval_comp, eval_C, eval_X, eval_add]
theorem taylor_eval_sub {R} [CommRing R] (r : R) (f : R[X]) (s : R) :
    (taylor r f).eval (s - r) = f.eval s := by 

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
r : R
f : R[X]
s : R
⊢ eval (s - r) ((taylor r) f) = eval s f

Next tactic:
rw [taylor_eval, sub_add_cancel]
theorem taylor_injective {R} [CommRing R] (r : R) : Function.Injective (taylor r) := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f : R✝[X]
R : Type u_2
inst✝ : CommRing R
r : R
⊢ Function.Injective ⇑(taylor r)

Next tactic:
intro f g h
theorem taylor_injective {R} [CommRing R] (r : R) : Function.Injective (taylor r) := by
  intro f g h
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
r : R
f g : R[X]
h : (taylor r) f = (taylor r) g
⊢ f = g

Next tactic:
apply_fun taylor (-r) at h
theorem taylor_injective {R} [CommRing R] (r : R) : Function.Injective (taylor r) := by
  intro f g h
  apply_fun taylor (-r) at h
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
r : R
f g : R[X]
h : (taylor (-r)) ((taylor r) f) = (taylor (-r)) ((taylor r) g)
⊢ f = g

Next tactic:
simpa only [taylor_apply, comp_assoc, add_comp, X_comp, C_comp, C_neg, neg_add_cancel_right,
    comp_X] using h
theorem eq_zero_of_hasseDeriv_eq_zero {R} [CommRing R] (f : R[X]) (r : R)
    (h : ∀ k, (hasseDeriv k f).eval r = 0) : f = 0 := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
f : R[X]
r : R
h : ∀ (k : ℕ), eval r ((hasseDeriv k) f) = 0
⊢ f = 0

Next tactic:
apply taylor_injective r
theorem eq_zero_of_hasseDeriv_eq_zero {R} [CommRing R] (f : R[X]) (r : R)
    (h : ∀ k, (hasseDeriv k f).eval r = 0) : f = 0 := by
  apply taylor_injective r
  

Proof state:
case a
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
f : R[X]
r : R
h : ∀ (k : ℕ), eval r ((hasseDeriv k) f) = 0
⊢ (taylor r) f = (taylor r) 0

Next tactic:
rw [LinearMap.map_zero]
theorem eq_zero_of_hasseDeriv_eq_zero {R} [CommRing R] (f : R[X]) (r : R)
    (h : ∀ k, (hasseDeriv k f).eval r = 0) : f = 0 := by
  apply taylor_injective r
  rw [LinearMap.map_zero]
  

Proof state:
case a
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
f : R[X]
r : R
h : ∀ (k : ℕ), eval r ((hasseDeriv k) f) = 0
⊢ (taylor r) f = 0

Next tactic:
ext k
theorem eq_zero_of_hasseDeriv_eq_zero {R} [CommRing R] (f : R[X]) (r : R)
    (h : ∀ k, (hasseDeriv k f).eval r = 0) : f = 0 := by
  apply taylor_injective r
  rw [LinearMap.map_zero]
  ext k
  

Proof state:
case a.a
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
f : R[X]
r : R
h : ∀ (k : ℕ), eval r ((hasseDeriv k) f) = 0
k : ℕ
⊢ coeff ((taylor r) f) k = coeff 0 k

Next tactic:
simp only [taylor_coeff, h, coeff_zero]
/-- Taylor's formula. -/
theorem sum_taylor_eq {R} [CommRing R] (f : R[X]) (r : R) :
    ((taylor r f).sum fun i a => C a * (X - C r) ^ i) = f := by
  

Proof state:
R✝ : Type u_1
inst✝¹ : Semiring R✝
r✝ : R✝
f✝ : R✝[X]
R : Type u_2
inst✝ : CommRing R
f : R[X]
r : R
⊢ (sum ((taylor r) f) fun i a => C a * (X - C r) ^ i) = f

Next tactic:
rw [← comp_eq_sum_left, sub_eq_add_neg, ← C_neg, ← taylor_apply, taylor_taylor, neg_add_self,
    taylor_zero]
theorem isSeparating_op_iff (𝒢 : Set C) : IsSeparating 𝒢.op ↔ IsCoseparating 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
⊢ IsSeparating (Set.op 𝒢) ↔ IsCoseparating 𝒢

Next tactic:
refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
theorem isSeparating_op_iff (𝒢 : Set C) : IsSeparating 𝒢.op ↔ IsCoseparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsSeparating (Set.op 𝒢)
X Y : C
f g : X ⟶ Y
hfg : ∀ G ∈ 𝒢, ∀ (h : Y ⟶ G), f ≫ h = g ≫ h
⊢ f = g

Next tactic:
refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
theorem isSeparating_op_iff (𝒢 : Set C) : IsSeparating 𝒢.op ↔ IsCoseparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsSeparating (Set.op 𝒢)
X Y : C
f g : X ⟶ Y
hfg : ∀ G ∈ 𝒢, ∀ (h : Y ⟶ G), f ≫ h = g ≫ h
G : Cᵒᵖ
hG : G ∈ Set.op 𝒢
h : G ⟶ op Y
⊢ (h ≫ f.op).unop = (h ≫ g.op).unop

Next tactic:
simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
theorem isSeparating_op_iff (𝒢 : Set C) : IsSeparating 𝒢.op ↔ IsCoseparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
  · 

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCoseparating 𝒢
X Y : Cᵒᵖ
f g : X ⟶ Y
hfg : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
⊢ f = g

Next tactic:
refine' Quiver.Hom.unop_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.op_inj _)
theorem isSeparating_op_iff (𝒢 : Set C) : IsSeparating 𝒢.op ↔ IsCoseparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)
    simpa only [unop_comp, Quiver.Hom.unop_op] using hfg _ (Set.mem_op.1 hG) _
  · refine' Quiver.Hom.unop_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.op_inj _)
    

Proof state:
case refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCoseparating 𝒢
X Y : Cᵒᵖ
f g : X ⟶ Y
hfg : ∀ G ∈ Set.op 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
G : C
hG : G ∈ 𝒢
h : X.unop ⟶ G
⊢ (f.unop ≫ h).op = (g.unop ≫ h).op

Next tactic:
simpa only [op_comp, Quiver.Hom.op_unop] using hfg _ (Set.op_mem_op.2 hG) _
theorem isCoseparating_op_iff (𝒢 : Set C) : IsCoseparating 𝒢.op ↔ IsSeparating 𝒢 := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
⊢ IsCoseparating (Set.op 𝒢) ↔ IsSeparating 𝒢

Next tactic:
refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
theorem isCoseparating_op_iff (𝒢 : Set C) : IsCoseparating 𝒢.op ↔ IsSeparating 𝒢 := by
  refine' ⟨fun h𝒢 X Y f g hfg => _, fun h𝒢 X Y f g hfg => _⟩
  · 

Proof state:
case refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
𝒢 : Set C
h𝒢 : IsCoseparating (Set.op 𝒢)
X Y : C
f g : X ⟶ Y
hfg : ∀ G ∈ 𝒢, ∀ (h : G ⟶ X), h ≫ f = h ≫ g
⊢ f = g

Next tactic:
refine' Quiver.Hom.op_inj (h𝒢 _ _ fun G hG h => Quiver.Hom.unop_inj _)