[GOAL]
m n b : ℕ
hm : m ≠ 1
hn : 0 < n
hb : log m n < b
⊢ multiplicity m n = ↑(card (Ico 1 (Part.get (multiplicity m n) (_ : multiplicity.Finite m n) + 1)))
[PROOFSTEP]
simp
[GOAL]
m n b : ℕ
hm : m ≠ 1
hn : 0 < n
hb : log m n < b
i : ℕ
⊢ i ∈ Ico 1 (Part.get (multiplicity m n) (_ : multiplicity.Finite m n) + 1) ↔ i ∈ filter (fun i => m ^ i ∣ n) (Ico 1 b)
[PROOFSTEP]
rw [mem_filter, mem_Ico, mem_Ico, lt_succ_iff, ← @PartENat.coe_le_coe i, PartENat.natCast_get, ←
  pow_dvd_iff_le_multiplicity, and_right_comm]
[GOAL]
m n b : ℕ
hm : m ≠ 1
hn : 0 < n
hb : log m n < b
i : ℕ
⊢ 1 ≤ i ∧ m ^ i ∣ n ↔ (1 ≤ i ∧ m ^ i ∣ n) ∧ i < b
[PROOFSTEP]
refine' (and_iff_left_of_imp fun h => lt_of_le_of_lt _ hb).symm
[GOAL]
m n b : ℕ
hm : m ≠ 1
hn : 0 < n
hb : log m n < b
i : ℕ
h : 1 ≤ i ∧ m ^ i ∣ n
⊢ i ≤ log m n
[PROOFSTEP]
cases' m with m
[GOAL]
case zero
n b : ℕ
hn : 0 < n
i : ℕ
hm : zero ≠ 1
hb : log zero n < b
h : 1 ≤ i ∧ zero ^ i ∣ n
⊢ i ≤ log zero n
[PROOFSTEP]
rw [zero_eq, zero_pow, zero_dvd_iff] at h
[GOAL]
case zero
n b : ℕ
hn : 0 < n
i : ℕ
hm : zero ≠ 1
hb : log zero n < b
h : 1 ≤ i ∧ n = 0
⊢ i ≤ log zero n
case zero n b : ℕ hn : 0 < n i : ℕ hm : zero ≠ 1 hb : log zero n < b h : 1 ≤ i ∧ 0 ^ i ∣ n ⊢ 0 < i
[PROOFSTEP]
exacts [(hn.ne' h.2).elim, h.1]
[GOAL]
case succ
n b : ℕ
hn : 0 < n
i m : ℕ
hm : succ m ≠ 1
hb : log (succ m) n < b
h : 1 ≤ i ∧ succ m ^ i ∣ n
⊢ i ≤ log (succ m) n
[PROOFSTEP]
exact le_log_of_pow_le (one_lt_iff_ne_zero_and_ne_one.2 ⟨m.succ_ne_zero, hm⟩) (le_of_dvd hn h.2)
[GOAL]
p : ℕ
hp : Prime p
b : ℕ
x✝ : log p 0 < b
⊢ multiplicity p 0! = ↑(∑ i in Ico 1 b, 0 / p ^ i)
[PROOFSTEP]
simp [Ico, hp.multiplicity_one]
[GOAL]
p : ℕ
hp : Prime p
n b : ℕ
hb : log p (n + 1) < b
⊢ multiplicity p (n + 1)! = multiplicity p n ! + multiplicity p (n + 1)
[PROOFSTEP]
rw [factorial_succ, hp.multiplicity_mul, add_comm]
[GOAL]
p : ℕ
hp : Prime p
n b : ℕ
hb : log p (n + 1) < b
⊢ multiplicity p n ! + multiplicity p (n + 1) =
    ↑(∑ i in Ico 1 b, n / p ^ i) + ↑(card (filter (fun i => p ^ i ∣ n + 1) (Ico 1 b)))
[PROOFSTEP]
rw [multiplicity_factorial hp ((log_mono_right <| le_succ _).trans_lt hb), ←
  multiplicity_eq_card_pow_dvd hp.ne_one (succ_pos _) hb]
[GOAL]
p : ℕ
hp : Prime p
n b : ℕ
hb : log p (n + 1) < b
⊢ ↑(∑ i in Ico 1 b, n / p ^ i) + ↑(card (filter (fun i => p ^ i ∣ n + 1) (Ico 1 b))) =
    ↑(∑ i in Ico 1 b, (n / p ^ i + if p ^ i ∣ n + 1 then 1 else 0))
[PROOFSTEP]
rw [sum_add_distrib, sum_boole]
[GOAL]
p : ℕ
hp : Prime p
n b : ℕ
hb : log p (n + 1) < b
⊢ ↑(∑ i in Ico 1 b, n / p ^ i) + ↑(card (filter (fun i => p ^ i ∣ n + 1) (Ico 1 b))) =
    ↑(∑ x in Ico 1 b, n / p ^ x + ↑(card (filter (fun x => p ^ x ∣ n + 1) (Ico 1 b))))
[PROOFSTEP]
simp
[GOAL]
n p : ℕ
hp : Prime p
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have hp' := hp.prime
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have h0 : 2 ≤ p := hp.two_le
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have h1 : 1 ≤ p * n + 1 := Nat.le_add_left _ _
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have h2 : p * n + 1 ≤ p * (n + 1)
[GOAL]
case h2
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
⊢ p * n + 1 ≤ p * (n + 1)
[PROOFSTEP]
linarith
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have h3 : p * n + 1 ≤ p * (n + 1) + 1
[GOAL]
case h3
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
⊢ p * n + 1 ≤ p * (n + 1) + 1
[PROOFSTEP]
linarith
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have hm : multiplicity p (p * n)! ≠ ⊤ :=
  by
  rw [Ne.def, eq_top_iff_not_finite, Classical.not_not, finite_nat_iff]
  exact ⟨hp.ne_one, factorial_pos _⟩
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
⊢ multiplicity p (p * n)! ≠ ⊤
[PROOFSTEP]
rw [Ne.def, eq_top_iff_not_finite, Classical.not_not, finite_nat_iff]
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
⊢ p ≠ 1 ∧ 0 < (p * n)!
[PROOFSTEP]
exact ⟨hp.ne_one, factorial_pos _⟩
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
hm : multiplicity p (p * n)! ≠ ⊤
⊢ multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
revert hm
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
⊢ multiplicity p (p * n)! ≠ ⊤ → multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
have h4 : ∀ m ∈ Ico (p * n + 1) (p * (n + 1)), multiplicity p m = 0 :=
  by
  intro m hm
  rw [multiplicity_eq_zero, ← not_dvd_iff_between_consec_multiples _ hp.pos]
  rw [mem_Ico] at hm
  exact ⟨n, lt_of_succ_le hm.1, hm.2⟩
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
⊢ ∀ (m : ℕ), m ∈ Ico (p * n + 1) (p * (n + 1)) → multiplicity p m = 0
[PROOFSTEP]
intro m hm
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
m : ℕ
hm : m ∈ Ico (p * n + 1) (p * (n + 1))
⊢ multiplicity p m = 0
[PROOFSTEP]
rw [multiplicity_eq_zero, ← not_dvd_iff_between_consec_multiples _ hp.pos]
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
m : ℕ
hm : m ∈ Ico (p * n + 1) (p * (n + 1))
⊢ ∃ k, p * k < m ∧ m < p * (k + 1)
[PROOFSTEP]
rw [mem_Ico] at hm
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
m : ℕ
hm : p * n + 1 ≤ m ∧ m < p * (n + 1)
⊢ ∃ k, p * k < m ∧ m < p * (k + 1)
[PROOFSTEP]
exact ⟨n, lt_of_succ_le hm.1, hm.2⟩
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
h4 : ∀ (m : ℕ), m ∈ Ico (p * n + 1) (p * (n + 1)) → multiplicity p m = 0
⊢ multiplicity p (p * n)! ≠ ⊤ → multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1
[PROOFSTEP]
simp_rw [← prod_Ico_id_eq_factorial, multiplicity.Finset.prod hp', ← sum_Ico_consecutive _ h1 h3, add_assoc]
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
h4 : ∀ (m : ℕ), m ∈ Ico (p * n + 1) (p * (n + 1)) → multiplicity p m = 0
⊢ ∑ x in Ico 1 (p * n + 1), multiplicity p x ≠ ⊤ →
    ∑ x in Ico 1 (p * n + 1), multiplicity p x + ∑ x in Ico (p * n + 1) (p * (n + 1) + 1), multiplicity p x =
      ∑ x in Ico 1 (p * n + 1), multiplicity p x + (multiplicity p (n + 1) + 1)
[PROOFSTEP]
intro h
[GOAL]
n p : ℕ
hp : Prime p
hp' : _root_.Prime p
h0 : 2 ≤ p
h1 : 1 ≤ p * n + 1
h2 : p * n + 1 ≤ p * (n + 1)
h3 : p * n + 1 ≤ p * (n + 1) + 1
h4 : ∀ (m : ℕ), m ∈ Ico (p * n + 1) (p * (n + 1)) → multiplicity p m = 0
h : ∑ x in Ico 1 (p * n + 1), multiplicity p x ≠ ⊤
⊢ ∑ x in Ico 1 (p * n + 1), multiplicity p x + ∑ x in Ico (p * n + 1) (p * (n + 1) + 1), multiplicity p x =
    ∑ x in Ico 1 (p * n + 1), multiplicity p x + (multiplicity p (n + 1) + 1)
[PROOFSTEP]
rw [PartENat.add_left_cancel_iff h, sum_Ico_succ_top h2, multiplicity.mul hp', hp.multiplicity_self, sum_congr rfl h4,
  sum_const_zero, zero_add, add_comm (1 : PartENat)]
[GOAL]
n p : ℕ
hp : Prime p
⊢ multiplicity p (p * n)! = multiplicity p n ! + ↑n
[PROOFSTEP]
induction' n with n ih
[GOAL]
case zero
p : ℕ
hp : Prime p
⊢ multiplicity p (p * zero)! = multiplicity p zero ! + ↑zero
[PROOFSTEP]
simp
[GOAL]
case succ
p : ℕ
hp : Prime p
n : ℕ
ih : multiplicity p (p * n)! = multiplicity p n ! + ↑n
⊢ multiplicity p (p * succ n)! = multiplicity p (succ n)! + ↑(succ n)
[PROOFSTEP]
simp only [succ_eq_add_one, multiplicity.mul, hp, hp.prime, ih, multiplicity_factorial_mul_succ, ← add_assoc,
  Nat.cast_one, Nat.cast_add, factorial_succ]
[GOAL]
case succ
p : ℕ
hp : Prime p
n : ℕ
ih : multiplicity p (p * n)! = multiplicity p n ! + ↑n
⊢ multiplicity p n ! + ↑n + multiplicity p (n + 1) + 1 = multiplicity p (n + 1) + multiplicity p n ! + ↑n + 1
[PROOFSTEP]
congr 1
[GOAL]
case succ.e_a
p : ℕ
hp : Prime p
n : ℕ
ih : multiplicity p (p * n)! = multiplicity p n ! + ↑n
⊢ multiplicity p n ! + ↑n + multiplicity p (n + 1) = multiplicity p (n + 1) + multiplicity p n ! + ↑n
[PROOFSTEP]
rw [add_comm, add_assoc]
[GOAL]
p n r b : ℕ
hp : Prime p
hbn : log p n < b
⊢ p ^ r ∣ n ! ↔ r ≤ ∑ i in Ico 1 b, n / p ^ i
[PROOFSTEP]
rw [← PartENat.coe_le_coe, ← hp.multiplicity_factorial hbn, ← pow_dvd_iff_le_multiplicity]
[GOAL]
p : ℕ
hp : Prime p
n : ℕ
⊢ multiplicity p n ! ≤ ↑(n / (p - 1))
[PROOFSTEP]
rw [hp.multiplicity_factorial (lt_succ_self _), PartENat.coe_le_coe]
[GOAL]
p : ℕ
hp : Prime p
n : ℕ
⊢ ∑ i in Ico 1 (succ (log p n)), n / p ^ i ≤ n / (p - 1)
[PROOFSTEP]
exact Nat.geom_sum_Ico_le hp.two_le _ _
[GOAL]
p n b k : ℕ
hp : Prime p
hkn : k ≤ n
⊢ ∑ i in Ico 1 b, n / p ^ i = ∑ i in Ico 1 b, (k + (n - k)) / p ^ i
[PROOFSTEP]
simp only [add_tsub_cancel_of_le hkn]
[GOAL]
p n b k : ℕ
hp : Prime p
hkn : k ≤ n
⊢ ∑ i in Ico 1 b, (k + (n - k)) / p ^ i =
    ∑ i in Ico 1 b, (k / p ^ i + (n - k) / p ^ i + if p ^ i ≤ k % p ^ i + (n - k) % p ^ i then 1 else 0)
[PROOFSTEP]
simp only [Nat.add_div (pow_pos hp.pos _)]
[GOAL]
p n b k : ℕ
hp : Prime p
hkn : k ≤ n
⊢ ∑ i in Ico 1 b, (k / p ^ i + (n - k) / p ^ i + if p ^ i ≤ k % p ^ i + (n - k) % p ^ i then 1 else 0) =
    ∑ i in Ico 1 b, k / p ^ i + ∑ i in Ico 1 b, (n - k) / p ^ i +
      card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))
[PROOFSTEP]
simp [sum_add_distrib, sum_boole]
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
⊢ multiplicity p (choose n k) = ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b)))
[PROOFSTEP]
have h₁ :
  multiplicity p (choose n k) + multiplicity p (k ! * (n - k)!) =
    ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i).card + multiplicity p (k ! * (n - k)!) :=
  by
  rw [← hp.multiplicity_mul, ← mul_assoc, choose_mul_factorial_mul_factorial hkn, hp.multiplicity_factorial hnb,
    hp.multiplicity_mul, hp.multiplicity_factorial ((log_mono_right hkn).trans_lt hnb),
    hp.multiplicity_factorial (lt_of_le_of_lt (log_mono_right tsub_le_self) hnb), multiplicity_choose_aux hp hkn]
  simp [add_comm]
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
⊢ multiplicity p (choose n k) + multiplicity p (k ! * (n - k)!) =
    ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) + multiplicity p (k ! * (n - k)!)
[PROOFSTEP]
rw [← hp.multiplicity_mul, ← mul_assoc, choose_mul_factorial_mul_factorial hkn, hp.multiplicity_factorial hnb,
  hp.multiplicity_mul, hp.multiplicity_factorial ((log_mono_right hkn).trans_lt hnb),
  hp.multiplicity_factorial (lt_of_le_of_lt (log_mono_right tsub_le_self) hnb), multiplicity_choose_aux hp hkn]
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
⊢ ↑(∑ i in Ico 1 b, k / p ^ i + ∑ i in Ico 1 b, (n - k) / p ^ i +
        card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) =
    ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) +
      (↑(∑ i in Ico 1 b, k / p ^ i) + ↑(∑ i in Ico 1 b, (n - k) / p ^ i))
[PROOFSTEP]
simp [add_comm]
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
h₁ :
  multiplicity p (choose n k) + multiplicity p (k ! * (n - k)!) =
    ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) + multiplicity p (k ! * (n - k)!)
⊢ multiplicity p (choose n k) = ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b)))
[PROOFSTEP]
refine (PartENat.add_right_cancel_iff ?_).1 h₁
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
h₁ :
  multiplicity p (choose n k) + multiplicity p (k ! * (n - k)!) =
    ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) + multiplicity p (k ! * (n - k)!)
⊢ multiplicity p (k ! * (n - k)!) ≠ ⊤
[PROOFSTEP]
apply PartENat.ne_top_iff_dom.2
[GOAL]
p n k b : ℕ
hp : Prime p
hkn : k ≤ n
hnb : log p n < b
h₁ :
  multiplicity p (choose n k) + multiplicity p (k ! * (n - k)!) =
    ↑(card (filter (fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i) (Ico 1 b))) + multiplicity p (k ! * (n - k)!)
⊢ (multiplicity p (k ! * (n - k)!)).Dom
[PROOFSTEP]
exact finite_nat_iff.2 ⟨hp.ne_one, mul_pos (factorial_pos k) (factorial_pos (n - k))⟩
[GOAL]
p : ℕ
hp : Prime p
x✝ : ℕ
⊢ multiplicity p x✝ ≤ multiplicity p (choose x✝ 0) + multiplicity p 0
[PROOFSTEP]
simp
[GOAL]
p : ℕ
hp : Prime p
n✝ : ℕ
⊢ multiplicity p 0 ≤ multiplicity p (choose 0 (n✝ + 1)) + multiplicity p (n✝ + 1)
[PROOFSTEP]
simp
[GOAL]
p : ℕ
hp : Prime p
n k : ℕ
⊢ multiplicity p (n + 1) ≤ multiplicity p (choose (n + 1) (k + 1)) + multiplicity p (k + 1)
[PROOFSTEP]
rw [← hp.multiplicity_mul]
[GOAL]
p : ℕ
hp : Prime p
n k : ℕ
⊢ multiplicity p (n + 1) ≤ multiplicity p (choose (n + 1) (k + 1) * (k + 1))
[PROOFSTEP]
refine' multiplicity_le_multiplicity_of_dvd_right _
[GOAL]
p : ℕ
hp : Prime p
n k : ℕ
⊢ n + 1 ∣ choose (n + 1) (k + 1) * (k + 1)
[PROOFSTEP]
rw [← succ_mul_choose_eq]
[GOAL]
p : ℕ
hp : Prime p
n k : ℕ
⊢ n + 1 ∣ succ n * choose n k
[PROOFSTEP]
exact dvd_mul_right _ _
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
⊢ multiplicity p (choose (p ^ n) k) + multiplicity p k ≤ ↑n
[PROOFSTEP]
have hdisj :
  Disjoint ((Ico 1 n.succ).filter fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i)
    ((Ico 1 n.succ).filter fun i => p ^ i ∣ k) :=
  by simp (config := { contextual := true }) [disjoint_right, *, dvd_iff_mod_eq_zero, Nat.mod_lt _ (pow_pos hp.pos _)]
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
⊢ Disjoint (filter (fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i) (Ico 1 (succ n)))
    (filter (fun i => p ^ i ∣ k) (Ico 1 (succ n)))
[PROOFSTEP]
simp (config := { contextual := true }) [disjoint_right, *, dvd_iff_mod_eq_zero, Nat.mod_lt _ (pow_pos hp.pos _)]
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
hdisj :
  Disjoint (filter (fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i) (Ico 1 (succ n)))
    (filter (fun i => p ^ i ∣ k) (Ico 1 (succ n)))
⊢ multiplicity p (choose (p ^ n) k) + multiplicity p k ≤ ↑n
[PROOFSTEP]
rw [multiplicity_choose hp hkn (lt_succ_self _),
  multiplicity_eq_card_pow_dvd (ne_of_gt hp.one_lt) hk0.bot_lt (lt_succ_of_le (log_mono_right hkn)), ← Nat.cast_add,
  PartENat.coe_le_coe, log_pow hp.one_lt, ← card_disjoint_union hdisj, filter_union_right]
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
hdisj :
  Disjoint (filter (fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i) (Ico 1 (succ n)))
    (filter (fun i => p ^ i ∣ k) (Ico 1 (succ n)))
⊢ card (filter (fun x => p ^ x ≤ k % p ^ x + (p ^ n - k) % p ^ x ∨ p ^ x ∣ k) (Ico 1 (succ n))) ≤ n
[PROOFSTEP]
have filter_le_Ico := (Ico 1 n.succ).card_filter_le fun x => p ^ x ≤ k % p ^ x + (p ^ n - k) % p ^ x ∨ p ^ x ∣ k
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
hdisj :
  Disjoint (filter (fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i) (Ico 1 (succ n)))
    (filter (fun i => p ^ i ∣ k) (Ico 1 (succ n)))
filter_le_Ico :
  card (filter (fun x => p ^ x ≤ k % p ^ x + (p ^ n - k) % p ^ x ∨ p ^ x ∣ k) (Ico 1 (succ n))) ≤ card (Ico 1 (succ n))
⊢ card (filter (fun x => p ^ x ≤ k % p ^ x + (p ^ n - k) % p ^ x ∨ p ^ x ∣ k) (Ico 1 (succ n))) ≤ n
[PROOFSTEP]
rwa [card_Ico 1 n.succ] at filter_le_Ico
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
⊢ ↑n ≤ multiplicity p (choose (p ^ n) k) + multiplicity p k
[PROOFSTEP]
rw [← hp.multiplicity_pow_self]
[GOAL]
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
⊢ multiplicity p (p ^ n) ≤ multiplicity p (choose (p ^ n) k) + multiplicity p k
[PROOFSTEP]
exact multiplicity_le_multiplicity_choose_add hp _ _
[GOAL]
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp : k ≠ p ^ n
⊢ p ∣ choose (p ^ n) k
[PROOFSTEP]
obtain hkp | hkp := hkp.symm.lt_or_lt
[GOAL]
case inl
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : p ^ n < k
⊢ p ∣ choose (p ^ n) k
[PROOFSTEP]
simp [choose_eq_zero_of_lt hkp]
[GOAL]
case inr
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : k < p ^ n
⊢ p ∣ choose (p ^ n) k
[PROOFSTEP]
refine' multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt _
[GOAL]
case inr
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : k < p ^ n
h : multiplicity p (choose (p ^ n) k) = 0
⊢ p ^ n ∣ k
[PROOFSTEP]
have H := hp.multiplicity_choose_prime_pow_add_multiplicity hkp.le hk
[GOAL]
case inr
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : k < p ^ n
h : multiplicity p (choose (p ^ n) k) = 0
H : multiplicity p (choose (p ^ n) k) + multiplicity p k = ↑n
⊢ p ^ n ∣ k
[PROOFSTEP]
rw [h, zero_add, eq_coe_iff] at H
[GOAL]
case inr
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : k < p ^ n
h : multiplicity p (choose (p ^ n) k) = 0
H : p ^ n ∣ k ∧ ¬p ^ (n + 1) ∣ k
⊢ p ^ n ∣ k
[PROOFSTEP]
exact H.1
[GOAL]
p n k : ℕ
hp : Prime p
⊢ p ∣ choose (p ^ n) k ↔ k ≠ 0 ∧ k ≠ p ^ n
[PROOFSTEP]
refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩
[GOAL]
case refine'_1
p n k : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) k
⊢ k ≠ 0
[PROOFSTEP]
rintro rfl
[GOAL]
case refine'_2
p n k : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) k
⊢ k ≠ p ^ n
[PROOFSTEP]
rintro rfl
[GOAL]
case refine'_1
p n : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) 0
⊢ False
[PROOFSTEP]
simp [hp.ne_one] at h
[GOAL]
case refine'_2
p n : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) (p ^ n)
⊢ False
[PROOFSTEP]
simp [hp.ne_one] at h
[GOAL]
⊢ ∀ {n : ℕ}, n ≠ 0 → multiplicity 2 n ! < ↑n
[PROOFSTEP]
have h2 := prime_two.prime
[GOAL]
h2 : _root_.Prime 2
⊢ ∀ {n : ℕ}, n ≠ 0 → multiplicity 2 n ! < ↑n
[PROOFSTEP]
refine' binaryRec _ _
[GOAL]
case refine'_1
h2 : _root_.Prime 2
⊢ 0 ≠ 0 → multiplicity 2 0! < ↑0
[PROOFSTEP]
exact fun h => False.elim <| h rfl
[GOAL]
case refine'_2
h2 : _root_.Prime 2
⊢ ∀ (b : Bool) (n : ℕ), (n ≠ 0 → multiplicity 2 n ! < ↑n) → bit b n ≠ 0 → multiplicity 2 (bit b n)! < ↑(bit b n)
[PROOFSTEP]
intro b n ih h
[GOAL]
case refine'_2
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
⊢ multiplicity 2 (bit b n)! < ↑(bit b n)
[PROOFSTEP]
by_cases hn : n = 0
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : n = 0
⊢ multiplicity 2 (bit b n)! < ↑(bit b n)
[PROOFSTEP]
subst hn
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : bit b 0 ≠ 0
⊢ multiplicity 2 (bit b 0)! < ↑(bit b 0)
[PROOFSTEP]
simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ multiplicity 2 (bit b 0)! < ↑(bit b 0)
[PROOFSTEP]
simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ multiplicity 2 (succ 0) < 1
[PROOFSTEP]
rw [Prime.multiplicity_one]
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ 0 < 1
case pos h2 : _root_.Prime 2 b : Bool ih : 0 ≠ 0 → multiplicity 2 0! < ↑0 h : b = true ⊢ Prime 2
[PROOFSTEP]
simp only [zero_lt_one]
[GOAL]
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ Prime 2
[PROOFSTEP]
decide
[GOAL]
case neg
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
⊢ multiplicity 2 (bit b n)! < ↑(bit b n)
[PROOFSTEP]
have : multiplicity 2 (2 * n)! < (2 * n : ℕ) :=
  by
  rw [prime_two.multiplicity_factorial_mul]
  refine' (PartENat.add_lt_add_right (ih hn) (PartENat.natCast_ne_top _)).trans_le _
  rw [two_mul]
  norm_cast
[GOAL]
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
⊢ multiplicity 2 (2 * n)! < ↑(2 * n)
[PROOFSTEP]
rw [prime_two.multiplicity_factorial_mul]
[GOAL]
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
⊢ multiplicity 2 n ! + ↑n < ↑(2 * n)
[PROOFSTEP]
refine' (PartENat.add_lt_add_right (ih hn) (PartENat.natCast_ne_top _)).trans_le _
[GOAL]
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
⊢ ↑n + ↑n ≤ ↑(2 * n)
[PROOFSTEP]
rw [two_mul]
[GOAL]
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
⊢ ↑n + ↑n ≤ ↑(n + n)
[PROOFSTEP]
norm_cast
[GOAL]
case neg
h2 : _root_.Prime 2
b : Bool
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
h : bit b n ≠ 0
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
⊢ multiplicity 2 (bit b n)! < ↑(bit b n)
[PROOFSTEP]
cases b
[GOAL]
case neg.false
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit false n ≠ 0
⊢ multiplicity 2 (bit false n)! < ↑(bit false n)
[PROOFSTEP]
simpa [bit0_eq_two_mul n]
[GOAL]
case neg.true
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit true n ≠ 0
⊢ multiplicity 2 (bit true n)! < ↑(bit true n)
[PROOFSTEP]
suffices multiplicity 2 (2 * n + 1) + multiplicity 2 (2 * n)! < ↑(2 * n) + 1 by
  simpa [succ_eq_add_one, multiplicity.mul, h2, prime_two, Nat.bit1_eq_succ_bit0, bit0_eq_two_mul n]
[GOAL]
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this✝ : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit true n ≠ 0
this : multiplicity 2 (2 * n + 1) + multiplicity 2 (2 * n)! < ↑(2 * n) + 1
⊢ multiplicity 2 (bit true n)! < ↑(bit true n)
[PROOFSTEP]
simpa [succ_eq_add_one, multiplicity.mul, h2, prime_two, Nat.bit1_eq_succ_bit0, bit0_eq_two_mul n]
[GOAL]
case neg.true
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit true n ≠ 0
⊢ multiplicity 2 (2 * n + 1) + multiplicity 2 (2 * n)! < ↑(2 * n) + 1
[PROOFSTEP]
rw [multiplicity_eq_zero.2 (two_not_dvd_two_mul_add_one n), zero_add]
[GOAL]
case neg.true
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit true n ≠ 0
⊢ multiplicity 2 (2 * n)! < ↑(2 * n) + 1
[PROOFSTEP]
refine' this.trans _
[GOAL]
case neg.true
h2 : _root_.Prime 2
n : ℕ
ih : n ≠ 0 → multiplicity 2 n ! < ↑n
hn : ¬n = 0
this : multiplicity 2 (2 * n)! < ↑(2 * n)
h : bit true n ≠ 0
⊢ ↑(2 * n) < ↑(2 * n) + 1
[PROOFSTEP]
exact_mod_cast lt_succ_self _


[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
⊢ G.map h ≫ G.map f = G.map h ≫ G.map g
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
⊢ (Iso.refl
          ((Cones.postcompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).hom).obj
              (G.mapCone (Fork.ofι h w))).pt).hom ≫
      Fork.ι (Fork.ofι (G.map h) (_ : G.map h ≫ G.map f = G.map h ≫ G.map g)) =
    Fork.ι ((Cones.postcompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).hom).obj (G.mapCone (Fork.ofι h w)))
[PROOFSTEP]
simp [Fork.ι]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝ : PreservesLimit (parallelPair f g) G
l : IsLimit (Fork.ofι h w)
⊢ G.map h ≫ G.map f = G.map h ≫ G.map g
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝ : ReflectsLimit (parallelPair f g) G
⊢ G.map h ≫ G.map f = G.map h ≫ G.map g
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : PreservesLimit (parallelPair f g) G
⊢ G.map (equalizer.ι f g) ≫ G.map f = G.map (equalizer.ι f g) ≫ G.map g
[PROOFSTEP]
simp only [← G.map_comp]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : PreservesLimit (parallelPair f g) G
⊢ G.map (equalizer.ι f g ≫ f) = G.map (equalizer.ι f g ≫ g)
[PROOFSTEP]
rw [equalizer.condition]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
i : IsIso (equalizerComparison f g G)
⊢ PreservesLimit (parallelPair f g) G
[PROOFSTEP]
apply preservesLimitOfPreservesLimitCone (equalizerIsEqualizer f g)
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
i : IsIso (equalizerComparison f g G)
⊢ IsLimit (G.mapCone (Fork.ofι (equalizer.ι f g) (_ : equalizer.ι f g ≫ f = equalizer.ι f g ≫ g)))
[PROOFSTEP]
apply (isLimitMapConeForkEquiv _ _).symm _
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
i : IsIso (equalizerComparison f g G)
⊢ IsLimit
    (Fork.ofι (G.map (equalizer.ι f g)) (_ : G.map (equalizer.ι f g) ≫ G.map f = G.map (equalizer.ι f g) ≫ G.map g))
[PROOFSTEP]
refine @IsLimit.ofPointIso _ _ _ _ _ _ _ (limit.isLimit (parallelPair (G.map f) (G.map g))) ?_
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝¹ : HasEqualizer f g
inst✝ : HasEqualizer (G.map f) (G.map g)
i : IsIso (equalizerComparison f g G)
⊢ IsIso
    (IsLimit.lift (limit.isLimit (parallelPair (G.map f) (G.map g)))
      (Fork.ofι (G.map (equalizer.ι f g)) (_ : G.map (equalizer.ι f g) ≫ G.map f = G.map (equalizer.ι f g) ≫ G.map g)))
[PROOFSTEP]
apply i
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝² : HasEqualizer f g
inst✝¹ : HasEqualizer (G.map f) (G.map g)
inst✝ : PreservesLimit (parallelPair f g) G
⊢ IsIso (equalizerComparison f g G)
[PROOFSTEP]
rw [← PreservesEqualizer.iso_hom]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = h ≫ g
inst✝² : HasEqualizer f g
inst✝¹ : HasEqualizer (G.map f) (G.map g)
inst✝ : PreservesLimit (parallelPair f g) G
⊢ IsIso (PreservesEqualizer.iso G f g).hom
[PROOFSTEP]
infer_instance
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ G.map f ≫ G.map h = G.map g ≫ G.map h
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ Cofork.π
        ((Cocones.precompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).inv).obj (G.mapCocone (Cofork.ofπ h w))) ≫
      (Iso.refl
          ((Cocones.precompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).inv).obj
              (G.mapCocone (Cofork.ofπ h w))).pt).hom =
    Cofork.π (Cofork.ofπ (G.map h) (_ : G.map f ≫ G.map h = G.map g ≫ G.map h))
[PROOFSTEP]
dsimp only [Cofork.π, Cofork.ofπ_ι_app]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ NatTrans.app
        ((Cocones.precompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).inv).obj (G.mapCocone (Cofork.ofπ h w))).ι
        WalkingParallelPair.one ≫
      (Iso.refl
          ((Cocones.precompose (diagramIsoParallelPair (parallelPair f g ⋙ G)).inv).obj
              (G.mapCocone (Cofork.ofπ h w))).pt).hom =
    G.map h
[PROOFSTEP]
dsimp
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
⊢ (𝟙 (G.obj Y) ≫ G.map h) ≫ 𝟙 (G.obj Z) = G.map h
[PROOFSTEP]
rw [Category.comp_id, Category.id_comp]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝ : PreservesColimit (parallelPair f g) G
l : IsColimit (Cofork.ofπ h w)
⊢ G.map f ≫ G.map h = G.map g ≫ G.map h
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝ : ReflectsColimit (parallelPair f g) G
⊢ G.map f ≫ G.map h = G.map g ≫ G.map h
[PROOFSTEP]
simp only [← G.map_comp, w]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : PreservesColimit (parallelPair f g) G
⊢ G.map f ≫ G.map (coequalizer.π f g) = G.map g ≫ G.map (coequalizer.π f g)
[PROOFSTEP]
simp only [← G.map_comp]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : PreservesColimit (parallelPair f g) G
⊢ G.map (f ≫ coequalizer.π f g) = G.map (g ≫ coequalizer.π f g)
[PROOFSTEP]
rw [coequalizer.condition]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
i : IsIso (coequalizerComparison f g G)
⊢ PreservesColimit (parallelPair f g) G
[PROOFSTEP]
apply preservesColimitOfPreservesColimitCocone (coequalizerIsCoequalizer f g)
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
i : IsIso (coequalizerComparison f g G)
⊢ IsColimit (G.mapCocone (Cofork.ofπ (coequalizer.π f g) (_ : f ≫ coequalizer.π f g = g ≫ coequalizer.π f g)))
[PROOFSTEP]
apply (isColimitMapCoconeCoforkEquiv _ _).symm _
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
i : IsIso (coequalizerComparison f g G)
⊢ IsColimit
    (Cofork.ofπ (G.map (coequalizer.π f g))
      (_ : G.map f ≫ G.map (coequalizer.π f g) = G.map g ≫ G.map (coequalizer.π f g)))
[PROOFSTEP]
refine @IsColimit.ofPointIso _ _ _ _ _ _ _ (colimit.isColimit (parallelPair (G.map f) (G.map g))) ?_
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝¹ : HasCoequalizer f g
inst✝ : HasCoequalizer (G.map f) (G.map g)
i : IsIso (coequalizerComparison f g G)
⊢ IsIso
    (IsColimit.desc (colimit.isColimit (parallelPair (G.map f) (G.map g)))
      (Cofork.ofπ (G.map (coequalizer.π f g))
        (_ : G.map f ≫ G.map (coequalizer.π f g) = G.map g ≫ G.map (coequalizer.π f g))))
[PROOFSTEP]
apply i
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
⊢ IsIso (coequalizerComparison f g G)
[PROOFSTEP]
rw [← PreservesCoequalizer.iso_hom]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
⊢ IsIso (PreservesCoequalizer.iso G f g).hom
[PROOFSTEP]
infer_instance
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
W : D
h k : G.obj (coequalizer f g) ⟶ W
⊢ G.map (coequalizer.π f g) ≫ h = G.map (coequalizer.π f g) ≫ k → h = k
[PROOFSTEP]
rw [← ι_comp_coequalizerComparison]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
W : D
h k : G.obj (coequalizer f g) ⟶ W
⊢ (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G) ≫ h =
      (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G) ≫ k →
    h = k
[PROOFSTEP]
haveI : Epi (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G) := by apply epi_comp
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
W : D
h k : G.obj (coequalizer f g) ⟶ W
⊢ Epi (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G)
[PROOFSTEP]
apply epi_comp
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
W : D
h k : G.obj (coequalizer f g) ⟶ W
this : Epi (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G)
⊢ (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G) ≫ h =
      (coequalizer.π (G.map f) (G.map g) ≫ coequalizerComparison f g G) ≫ k →
    h = k
[PROOFSTEP]
apply (cancel_epi _).1
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
⊢ G.map (coequalizer.π f g) ≫ (PreservesCoequalizer.iso G f g).inv = coequalizer.π (G.map f) (G.map g)
[PROOFSTEP]
rw [← ι_comp_coequalizerComparison_assoc, ← PreservesCoequalizer.iso_hom, Iso.hom_inv_id, comp_id]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝² : HasCoequalizer f g
inst✝¹ : HasCoequalizer (G.map f) (G.map g)
inst✝ : PreservesColimit (parallelPair f g) G
W : D
k : G.obj Y ⟶ W
wk : G.map f ≫ k = G.map g ≫ k
⊢ G.map (coequalizer.π f g) ≫ (PreservesCoequalizer.iso G f g).inv ≫ coequalizer.desc k wk = k
[PROOFSTEP]
rw [← Category.assoc, map_π_preserves_coequalizer_inv, coequalizer.π_desc]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = g ≫ h
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
⊢ G.map (coequalizer.π f g) ≫
      (PreservesCoequalizer.iso G f g).inv ≫ colimMap (parallelPairHom (G.map f) (G.map g) f' g' p q wf wg) =
    q ≫ coequalizer.π f' g'
[PROOFSTEP]
rw [← Category.assoc, map_π_preserves_coequalizer_inv, ι_colimMap, parallelPairHom_app_one]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
⊢ G.map (coequalizer.π f g) ≫
      (PreservesCoequalizer.iso G f g).inv ≫
        colimMap (parallelPairHom (G.map f) (G.map g) f' g' p q wf wg) ≫ coequalizer.desc h wh =
    q ≫ h
[PROOFSTEP]
slice_lhs 1 3 => rw [map_π_preserves_coequalizer_inv_colimMap]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| G.map (coequalizer.π f g) ≫
    (PreservesCoequalizer.iso G f g).inv ≫ colimMap (parallelPairHom (G.map f) (G.map g) f' g' p q wf wg)
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.desc h wh
[PROOFSTEP]
rw [map_π_preserves_coequalizer_inv_colimMap]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| G.map (coequalizer.π f g) ≫
    (PreservesCoequalizer.iso G f g).inv ≫ colimMap (parallelPairHom (G.map f) (G.map g) f' g' p q wf wg)
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.desc h wh
[PROOFSTEP]
rw [map_π_preserves_coequalizer_inv_colimMap]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| G.map (coequalizer.π f g) ≫
    (PreservesCoequalizer.iso G f g).inv ≫ colimMap (parallelPairHom (G.map f) (G.map g) f' g' p q wf wg)
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.desc h wh
[PROOFSTEP]
rw [map_π_preserves_coequalizer_inv_colimMap]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
⊢ (q ≫ coequalizer.π f' g') ≫ coequalizer.desc h wh = q ≫ h
[PROOFSTEP]
slice_lhs 2 3 => rw [coequalizer.π_desc]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.π f' g' ≫ coequalizer.desc h wh
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| q
[PROOFSTEP]
rw [coequalizer.π_desc]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.π f' g' ≫ coequalizer.desc h wh
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| q
[PROOFSTEP]
rw [coequalizer.π_desc]
[GOAL]
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| coequalizer.π f' g' ≫ coequalizer.desc h wh
case a
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f g : X ⟶ Y
h✝ : Y ⟶ Z
w : f ≫ h✝ = g ≫ h✝
inst✝³ : HasCoequalizer f g
inst✝² : HasCoequalizer (G.map f) (G.map g)
inst✝¹ : PreservesColimit (parallelPair f g) G
X' Y' : D
f' g' : X' ⟶ Y'
inst✝ : HasCoequalizer f' g'
p : G.obj X ⟶ X'
q : G.obj Y ⟶ Y'
wf : G.map f ≫ q = p ≫ f'
wg : G.map g ≫ q = p ≫ g'
Z' : D
h : Y' ⟶ Z'
wh : f' ≫ h = g' ≫ h
| q
[PROOFSTEP]
rw [coequalizer.π_desc]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f✝ g✝ : X ⟶ Y
h : Y ⟶ Z
w : f✝ ≫ h = g✝ ≫ h
inst✝³ : HasCoequalizer f✝ g✝
inst✝² : HasCoequalizer (G.map f✝) (G.map g✝)
inst✝¹ : PreservesColimit (parallelPair f✝ g✝) G
f g : X ⟶ Y
inst✝ : HasSplitCoequalizer f g
⊢ PreservesColimit (parallelPair f g) G
[PROOFSTEP]
apply preservesColimitOfPreservesColimitCocone (HasSplitCoequalizer.isSplitCoequalizer f g).isCoequalizer
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
G : C ⥤ D
X Y Z : C
f✝ g✝ : X ⟶ Y
h : Y ⟶ Z
w : f✝ ≫ h = g✝ ≫ h
inst✝³ : HasCoequalizer f✝ g✝
inst✝² : HasCoequalizer (G.map f✝) (G.map g✝)
inst✝¹ : PreservesColimit (parallelPair f✝ g✝) G
f g : X ⟶ Y
inst✝ : HasSplitCoequalizer f g
⊢ IsColimit (G.mapCocone (IsSplitCoequalizer.asCofork (HasSplitCoequalizer.isSplitCoequalizer f g)))
[PROOFSTEP]
apply (isColimitMapCoconeCoforkEquiv G _).symm ((HasSplitCoequalizer.isSplitCoequalizer f g).map G).isCoequalizer


[GOAL]
α : Type u
inst✝³ : OrderedCancelCommMonoid α
β : Type u_1
inst✝² : One β
inst✝¹ : Mul β
inst✝ : Pow β ℕ
f : β → α
hf : Injective f
one : f 1 = 1
mul : ∀ (x y : β), f (x * y) = f x * f y
npow : ∀ (x : β) (n : ℕ), f (x ^ n) = f x ^ n
src✝ : OrderedCommMonoid β := orderedCommMonoid f hf one mul npow
a b c : β
bc : f (a * b) ≤ f (a * c)
⊢ f a * f b ≤ f a * f c
[PROOFSTEP]
rwa [← mul, ← mul]


[GOAL]
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
u : Rˣ
⊢ ↑(constantCoeff R) (invUnitsSub u) = 1 /ₚ u
[PROOFSTEP]
rw [← coeff_zero_eq_constantCoeff_apply, coeff_invUnitsSub, zero_add, pow_one]
[GOAL]
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
u : Rˣ
⊢ invUnitsSub u * X = invUnitsSub u * ↑(C R) ↑u - 1
[PROOFSTEP]
ext (_ | n)
[GOAL]
case h.zero
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
u : Rˣ
⊢ ↑(coeff R Nat.zero) (invUnitsSub u * X) = ↑(coeff R Nat.zero) (invUnitsSub u * ↑(C R) ↑u - 1)
[PROOFSTEP]
simp
[GOAL]
case h.succ
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
u : Rˣ
n : ℕ
⊢ ↑(coeff R (Nat.succ n)) (invUnitsSub u * X) = ↑(coeff R (Nat.succ n)) (invUnitsSub u * ↑(C R) ↑u - 1)
[PROOFSTEP]
simp [n.succ_ne_zero, pow_succ]
[GOAL]
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
u : Rˣ
⊢ invUnitsSub u * (↑(C R) ↑u - X) = 1
[PROOFSTEP]
simp [mul_sub, sub_sub_cancel]
[GOAL]
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
f : R →+* S
u : Rˣ
⊢ ↑(map f) (invUnitsSub u) = invUnitsSub (↑(Units.map ↑f) u)
[PROOFSTEP]
ext
[GOAL]
case h
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
f : R →+* S
u : Rˣ
n✝ : ℕ
⊢ ↑(coeff S n✝) (↑(map f) (invUnitsSub u)) = ↑(coeff S n✝) (invUnitsSub (↑(Units.map ↑f) u))
[PROOFSTEP]
simp only [← map_pow, coeff_map, coeff_invUnitsSub, one_divp]
[GOAL]
case h
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : Ring S
f : R →+* S
u : Rˣ
n✝ : ℕ
⊢ ↑f ↑(u ^ (n✝ + 1))⁻¹ = ↑(↑(Units.map ↑f) (u ^ (n✝ + 1)))⁻¹
[PROOFSTEP]
rfl
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(constantCoeff A) (exp A) = 1
[PROOFSTEP]
rw [← coeff_zero_eq_constantCoeff_apply, coeff_exp]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(algebraMap ℚ A) (1 / ↑0!) = 1
[PROOFSTEP]
simp
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(coeff A (bit0 n)) (sin A) = 0
[PROOFSTEP]
rw [sin, coeff_mk, if_pos (even_bit0 n)]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(coeff A (bit1 n)) (sin A) = (-1) ^ n * ↑(coeff A (bit1 n)) (exp A)
[PROOFSTEP]
rw [sin, coeff_mk, if_neg n.not_even_bit1, Nat.bit1_div_two, ← mul_one_div, map_mul, map_pow, map_neg, map_one,
  coeff_exp]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(coeff A (bit0 n)) (cos A) = (-1) ^ n * ↑(coeff A (bit0 n)) (exp A)
[PROOFSTEP]
rw [cos, coeff_mk, if_pos (even_bit0 n), Nat.bit0_div_two, ← mul_one_div, map_mul, map_pow, map_neg, map_one, coeff_exp]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(coeff A (bit1 n)) (cos A) = 0
[PROOFSTEP]
rw [cos, coeff_mk, if_neg n.not_even_bit1]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(map f) (exp A) = exp A'
[PROOFSTEP]
ext
[GOAL]
case h
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
n✝ : ℕ
⊢ ↑(coeff A' n✝) (↑(map f) (exp A)) = ↑(coeff A' n✝) (exp A')
[PROOFSTEP]
simp
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(map f) (sin A) = sin A'
[PROOFSTEP]
ext
[GOAL]
case h
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
n✝ : ℕ
⊢ ↑(coeff A' n✝) (↑(map f) (sin A)) = ↑(coeff A' n✝) (sin A')
[PROOFSTEP]
simp [sin, apply_ite f]
[GOAL]
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
⊢ ↑(map f) (cos A) = cos A'
[PROOFSTEP]
ext
[GOAL]
case h
A : Type u_1
A' : Type u_2
inst✝⁷ : Ring A
inst✝⁶ : Ring A'
inst✝⁵ : Algebra ℚ A
inst✝⁴ : Algebra ℚ A'
inst✝³ : Ring A
inst✝² : Ring A'
inst✝¹ : Algebra ℚ A
inst✝ : Algebra ℚ A'
n : ℕ
f : A →+* A'
n✝ : ℕ
⊢ ↑(coeff A' n✝) (↑(map f) (cos A)) = ↑(coeff A' n✝) (cos A')
[PROOFSTEP]
simp [cos, apply_ite f]
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
⊢ ↑(rescale a) (exp A) * ↑(rescale b) (exp A) = ↑(rescale (a + b)) (exp A)
[PROOFSTEP]
ext n
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n : ℕ
⊢ ↑(coeff A n) (↑(rescale a) (exp A) * ↑(rescale b) (exp A)) = ↑(coeff A n) (↑(rescale (a + b)) (exp A))
[PROOFSTEP]
simp only [coeff_mul, exp, rescale, coeff_mk, MonoidHom.coe_mk, OneHom.coe_mk, coe_mk, factorial,
  Nat.sum_antidiagonal_eq_sum_range_succ_mk, add_pow, sum_mul]
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n : ℕ
⊢ (Finset.sum (Finset.range (succ n)) fun x =>
      a ^ x * ↑(algebraMap ℚ A) (1 / ↑x !) * (b ^ (n - x) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!))) =
    Finset.sum (Finset.range (n + 1)) fun x => a ^ x * b ^ (n - x) * ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !)
[PROOFSTEP]
apply sum_congr rfl
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n : ℕ
⊢ ∀ (x : ℕ),
    x ∈ Finset.range (succ n) →
      a ^ x * ↑(algebraMap ℚ A) (1 / ↑x !) * (b ^ (n - x) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
        a ^ x * b ^ (n - x) * ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !)
[PROOFSTEP]
rintro x hx
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ a ^ x * ↑(algebraMap ℚ A) (1 / ↑x !) * (b ^ (n - x) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !)
[PROOFSTEP]
suffices
  a ^ x * b ^ (n - x) * (algebraMap ℚ A (1 / ↑x.factorial) * algebraMap ℚ A (1 / ↑(n - x).factorial)) =
    a ^ x * b ^ (n - x) * (↑(n.choose x) * (algebraMap ℚ A) (1 / ↑n.factorial))
  by convert this using 1 <;> ring
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
this :
  a ^ x * b ^ (n - x) * (↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * (↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !))
⊢ a ^ x * ↑(algebraMap ℚ A) (1 / ↑x !) * (b ^ (n - x) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !)
[PROOFSTEP]
convert this using 1
[GOAL]
case h.e'_2
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
this :
  a ^ x * b ^ (n - x) * (↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * (↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !))
⊢ a ^ x * ↑(algebraMap ℚ A) (1 / ↑x !) * (b ^ (n - x) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * (↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!))
[PROOFSTEP]
ring
[GOAL]
case h.e'_3
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
this :
  a ^ x * b ^ (n - x) * (↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * (↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !))
⊢ a ^ x * b ^ (n - x) * ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !) =
    a ^ x * b ^ (n - x) * (↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !))
[PROOFSTEP]
ring
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ a ^ x * b ^ (n - x) * (↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!)) =
    a ^ x * b ^ (n - x) * (↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !))
[PROOFSTEP]
congr 1
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑(algebraMap ℚ A) (1 / ↑x !) * ↑(algebraMap ℚ A) (1 / ↑(n - x)!) = ↑(Nat.choose n x) * ↑(algebraMap ℚ A) (1 / ↑n !)
[PROOFSTEP]
rw [← map_natCast (algebraMap ℚ A) (n.choose x), ← map_mul, ← map_mul]
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑(algebraMap ℚ A) (1 / ↑x ! * (1 / ↑(n - x)!)) = ↑(algebraMap ℚ A) (↑(Nat.choose n x) * (1 / ↑n !))
[PROOFSTEP]
refine' RingHom.congr_arg _ _
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ 1 / ↑x ! * (1 / ↑(n - x)!) = ↑(Nat.choose n x) * (1 / ↑n !)
[PROOFSTEP]
rw [mul_one_div (↑(n.choose x) : ℚ), one_div_mul_one_div]
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ 1 / (↑x ! * ↑(n - x)!) = ↑(Nat.choose n x) / ↑n !
[PROOFSTEP]
symm
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑(Nat.choose n x) / ↑n ! = 1 / (↑x ! * ↑(n - x)!)
[PROOFSTEP]
rw [div_eq_iff, div_mul_eq_mul_div, one_mul, choose_eq_factorial_div_factorial]
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑(n ! / (x ! * (n - x)!)) = ↑n ! / (↑x ! * ↑(n - x)!)
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ x ≤ n
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑n ! ≠ 0
[PROOFSTEP]
norm_cast
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑(n ! / (x ! * (n - x)!)) = ↑n ! / ↑(x ! * (n - x)!)
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ x ≤ n
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑n ! ≠ 0
[PROOFSTEP]
rw [cast_div_charZero]
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ x ! * (n - x)! ∣ n !
[PROOFSTEP]
apply factorial_mul_factorial_dvd_factorial (mem_range_succ_iff.1 hx)
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ x ≤ n
[PROOFSTEP]
apply mem_range_succ_iff.1 hx
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
⊢ ↑n ! ≠ 0
[PROOFSTEP]
rintro h
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
h : ↑n ! = 0
⊢ False
[PROOFSTEP]
apply factorial_ne_zero n
[GOAL]
case h.e_a
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
a b : A
n x : ℕ
hx : x ∈ Finset.range (succ n)
h : ↑n ! = 0
⊢ n ! = 0
[PROOFSTEP]
rw [cast_eq_zero.1 h]
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
⊢ exp A * ↑evalNegHom (exp A) = 1
[PROOFSTEP]
convert exp_mul_exp_eq_exp_add (1 : A) (-1)
[GOAL]
case h.e'_2.h.e'_5
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
⊢ exp A = ↑(rescale 1) (exp A)
[PROOFSTEP]
simp
[GOAL]
case h.e'_3
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
⊢ 1 = ↑(rescale (1 + -1)) (exp A)
[PROOFSTEP]
simp
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
k : ℕ
⊢ exp A ^ k = ↑(rescale ↑k) (exp A)
[PROOFSTEP]
induction' k with k h
[GOAL]
case zero
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
⊢ exp A ^ zero = ↑(rescale ↑zero) (exp A)
[PROOFSTEP]
simp only [rescale_zero, constantCoeff_exp, Function.comp_apply, map_one, cast_zero, zero_eq, pow_zero (exp A),
  coe_comp]
[GOAL]
case succ
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
k : ℕ
h : exp A ^ k = ↑(rescale ↑k) (exp A)
⊢ exp A ^ succ k = ↑(rescale ↑(succ k)) (exp A)
[PROOFSTEP]
simpa only [succ_eq_add_one, cast_add, ← exp_mul_exp_eq_exp_add (k : A), ← h, cast_one, id_apply, rescale_one] using
  pow_succ' (exp A) k
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
n : ℕ
⊢ (Finset.sum (Finset.range n) fun k => exp A ^ k) =
    mk fun p => Finset.sum (Finset.range n) fun k => ↑(k ^ p) * ↑(algebraMap ℚ A) (↑p !)⁻¹
[PROOFSTEP]
simp only [exp_pow_eq_rescale_exp, rescale]
[GOAL]
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
n : ℕ
⊢ (Finset.sum (Finset.range n) fun x =>
      ↑{
            toMonoidHom :=
              {
                toOneHom :=
                  { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                    map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                map_mul' :=
                  (_ :
                    ∀ (f g : PowerSeries A),
                      OneHom.toFun
                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                          (f * g) =
                        OneHom.toFun
                            { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                              map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                            f *
                          OneHom.toFun
                            { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                              map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                            g) },
            map_zero' :=
              (_ :
                OneHom.toFun
                    (↑{
                        toOneHom :=
                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                        map_mul' :=
                          (_ :
                            ∀ (f g : PowerSeries A),
                              OneHom.toFun
                                  { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                    map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                  (f * g) =
                                OneHom.toFun
                                    { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                      map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                    f *
                                  OneHom.toFun
                                    { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                      map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                    g) })
                    0 =
                  0),
            map_add' :=
              (_ :
                ∀ (x_1 y : PowerSeries A),
                  OneHom.toFun
                      (↑{
                          toOneHom :=
                            { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                              map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                          map_mul' :=
                            (_ :
                              ∀ (f g : PowerSeries A),
                                OneHom.toFun
                                    { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                      map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                    (f * g) =
                                  OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      f *
                                    OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      g) })
                      (x_1 + y) =
                    OneHom.toFun
                        (↑{
                            toOneHom :=
                              { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                            map_mul' :=
                              (_ :
                                ∀ (f g : PowerSeries A),
                                  OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      (f * g) =
                                    OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        f *
                                      OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        g) })
                        x_1 +
                      OneHom.toFun
                        (↑{
                            toOneHom :=
                              { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                            map_mul' :=
                              (_ :
                                ∀ (f g : PowerSeries A),
                                  OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      (f * g) =
                                    OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        f *
                                      OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        g) })
                        y) }
        (exp A)) =
    mk fun p => Finset.sum (Finset.range n) fun x => ↑(x ^ p) * ↑(algebraMap ℚ A) (↑p !)⁻¹
[PROOFSTEP]
ext
[GOAL]
case h
A : Type u_1
inst✝¹ : CommRing A
inst✝ : Algebra ℚ A
n n✝ : ℕ
⊢ ↑(coeff A n✝)
      (Finset.sum (Finset.range n) fun x =>
        ↑{
              toMonoidHom :=
                {
                  toOneHom :=
                    { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                      map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                  map_mul' :=
                    (_ :
                      ∀ (f g : PowerSeries A),
                        OneHom.toFun
                            { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                              map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                            (f * g) =
                          OneHom.toFun
                              { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                              f *
                            OneHom.toFun
                              { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                              g) },
              map_zero' :=
                (_ :
                  OneHom.toFun
                      (↑{
                          toOneHom :=
                            { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                              map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                          map_mul' :=
                            (_ :
                              ∀ (f g : PowerSeries A),
                                OneHom.toFun
                                    { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                      map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                    (f * g) =
                                  OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      f *
                                    OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      g) })
                      0 =
                    0),
              map_add' :=
                (_ :
                  ∀ (x_1 y : PowerSeries A),
                    OneHom.toFun
                        (↑{
                            toOneHom :=
                              { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                            map_mul' :=
                              (_ :
                                ∀ (f g : PowerSeries A),
                                  OneHom.toFun
                                      { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                        map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                      (f * g) =
                                    OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        f *
                                      OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        g) })
                        (x_1 + y) =
                      OneHom.toFun
                          (↑{
                              toOneHom :=
                                { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                  map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                              map_mul' :=
                                (_ :
                                  ∀ (f g : PowerSeries A),
                                    OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        (f * g) =
                                      OneHom.toFun
                                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                          f *
                                        OneHom.toFun
                                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                          g) })
                          x_1 +
                        OneHom.toFun
                          (↑{
                              toOneHom :=
                                { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                  map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) },
                              map_mul' :=
                                (_ :
                                  ∀ (f g : PowerSeries A),
                                    OneHom.toFun
                                        { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                          map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                        (f * g) =
                                      OneHom.toFun
                                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                          f *
                                        OneHom.toFun
                                          { toFun := fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f,
                                            map_one' := (_ : (fun f => mk fun n => ↑x ^ n * ↑(coeff A n) f) 1 = 1) }
                                          g) })
                          y) }
          (exp A)) =
    ↑(coeff A n✝) (mk fun p => Finset.sum (Finset.range n) fun x => ↑(x ^ p) * ↑(algebraMap ℚ A) (↑p !)⁻¹)
[PROOFSTEP]
simp only [one_div, coeff_mk, cast_pow, coe_mk, MonoidHom.coe_mk, OneHom.coe_mk, coeff_exp, factorial,
  LinearMap.map_sum]