l3lab/ntp-mathlib huggingface dataset:
theorem multiplicity_choose_prime_pow_add_multiplicity (hp : p.Prime) (hkn : k ≤ p ^ n)
    (hk0 : k ≠ 0) : multiplicity p (choose (p ^ n) k) + multiplicity p k = n :=
  le_antisymm
    (by
      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 _)]
      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]
      

Proof state:
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

Next tactic:
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
theorem multiplicity_choose_prime_pow_add_multiplicity (hp : p.Prime) (hkn : k ≤ p ^ n)
    (hk0 : k ≠ 0) : multiplicity p (choose (p ^ n) k) + multiplicity p k = n :=
  le_antisymm
    (by
      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 _)]
      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]
      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
      

Proof state:
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

Next tactic:
rwa [card_Ico 1 n.succ] at filter_le_Ico
theorem multiplicity_choose_prime_pow_add_multiplicity (hp : p.Prime) (hkn : k ≤ p ^ n)
    (hk0 : k ≠ 0) : multiplicity p (choose (p ^ n) k) + multiplicity p k = n :=
  le_antisymm
    (by
      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 _)]
      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]
      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
      rwa [card_Ico 1 n.succ] at filter_le_Ico)
    (by 

Proof state:
p n k : ℕ
hp : Prime p
hkn : k ≤ p ^ n
hk0 : k ≠ 0
⊢ ↑n ≤ multiplicity p (choose (p ^ n) k) + multiplicity p k

Next tactic:
rw [← hp.multiplicity_pow_self]
theorem multiplicity_choose_prime_pow_add_multiplicity (hp : p.Prime) (hkn : k ≤ p ^ n)
    (hk0 : k ≠ 0) : multiplicity p (choose (p ^ n) k) + multiplicity p k = n :=
  le_antisymm
    (by
      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 _)]
      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]
      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
      rwa [card_Ico 1 n.succ] at filter_le_Ico)
    (by rw [← hp.multiplicity_pow_self]; 

Proof state:
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

Next tactic:
exact multiplicity_le_multiplicity_choose_add hp _ _
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  

Proof state:
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp : k ≠ p ^ n
⊢ p ∣ choose (p ^ n) k

Next tactic:
obtain hkp | hkp := hkp.symm.lt_or_lt
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  obtain hkp | hkp := hkp.symm.lt_or_lt
  · 

Proof state:
case inl
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : p ^ n < k
⊢ p ∣ choose (p ^ n) k

Next tactic:
simp [choose_eq_zero_of_lt hkp]
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  obtain hkp | hkp := hkp.symm.lt_or_lt
  · simp [choose_eq_zero_of_lt hkp]
  

Proof state:
case inr
p n k : ℕ
hp : Prime p
hk : k ≠ 0
hkp✝ : k ≠ p ^ n
hkp : k < p ^ n
⊢ p ∣ choose (p ^ n) k

Next tactic:
refine' multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt _
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  obtain hkp | hkp := hkp.symm.lt_or_lt
  · simp [choose_eq_zero_of_lt hkp]
  refine' multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt _
  

Proof state:
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

Next tactic:
have H := hp.multiplicity_choose_prime_pow_add_multiplicity hkp.le hk
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  obtain hkp | hkp := hkp.symm.lt_or_lt
  · simp [choose_eq_zero_of_lt hkp]
  refine' multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt _
  have H := hp.multiplicity_choose_prime_pow_add_multiplicity hkp.le hk
  

Proof state:
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

Next tactic:
rw [h, zero_add, eq_coe_iff] at H
theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by
  obtain hkp | hkp := hkp.symm.lt_or_lt
  · simp [choose_eq_zero_of_lt hkp]
  refine' multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt _
  have H := hp.multiplicity_choose_prime_pow_add_multiplicity hkp.le hk
  rw [h, zero_add, eq_coe_iff] at H
  

Proof state:
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

Next tactic:
exact H.1
theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by
  

Proof state:
p n k : ℕ
hp : Prime p
⊢ p ∣ choose (p ^ n) k ↔ k ≠ 0 ∧ k ≠ p ^ n

Next tactic:
refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩
theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by
  refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩ <;> 

Proof state:
case refine'_1
p n k : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) k
⊢ k ≠ 0

Next tactic:
rintro rfl
theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by
  refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩ <;> 

Proof state:
case refine'_2
p n k : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) k
⊢ k ≠ p ^ n

Next tactic:
rintro rfl
theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by
  refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩ <;> rintro rfl <;>
    

Proof state:
case refine'_1
p n : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) 0
⊢ False

Next tactic:
simp [hp.ne_one] at h
theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by
  refine' ⟨fun h => ⟨_, _⟩, fun h => dvd_choose_pow hp h.1 h.2⟩ <;> rintro rfl <;>
    

Proof state:
case refine'_2
p n : ℕ
hp : Prime p
h : p ∣ choose (p ^ n) (p ^ n)
⊢ False

Next tactic:
simp [hp.ne_one] at h
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  

Proof state:
⊢ ∀ {n : ℕ}, n ≠ 0 → multiplicity 2 n ! < ↑n

Next tactic:
have h2 := prime_two.prime
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  

Proof state:
h2 : _root_.Prime 2
⊢ ∀ {n : ℕ}, n ≠ 0 → multiplicity 2 n ! < ↑n

Next tactic:
refine' binaryRec _ _
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · 

Proof state:
case refine'_1
h2 : _root_.Prime 2
⊢ 0 ≠ 0 → multiplicity 2 0! < ↑0

Next tactic:
exact fun h => False.elim <| h rfl
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · 

Proof state:
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)

Next tactic:
intro b n ih h
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    

Proof state:
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)

Next tactic:
by_cases hn : n = 0
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · 

Proof state:
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)

Next tactic:
subst hn
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      

Proof state:
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)

Next tactic:
simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      

Proof state:
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)

Next tactic:
simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      

Proof state:
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ multiplicity 2 (succ 0) < 1

Next tactic:
rw [Prime.multiplicity_one]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      

Proof state:
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

Next tactic:
simp only [zero_lt_one]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      

Proof state:
case pos
h2 : _root_.Prime 2
b : Bool
ih : 0 ≠ 0 → multiplicity 2 0! < ↑0
h : b = true
⊢ Prime 2

Next tactic:
decide
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    

Proof state:
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)

Next tactic:
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
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    have : multiplicity 2 (2 * n)! < (2 * n : ℕ) := by
      

Proof state:
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)

Next tactic:
rw [prime_two.multiplicity_factorial_mul]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    have : multiplicity 2 (2 * n)! < (2 * n : ℕ) := by
      rw [prime_two.multiplicity_factorial_mul]
      

Proof state:
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)

Next tactic:
refine' (PartENat.add_lt_add_right (ih hn) (PartENat.natCast_ne_top _)).trans_le _
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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 _
      

Proof state:
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)

Next tactic:
rw [two_mul]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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]
      

Proof state:
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)

Next tactic:
norm_cast
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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
    

Proof state:
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)

Next tactic:
cases b
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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
    cases b
    · 

Proof state:
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)

Next tactic:
simpa [bit0_eq_two_mul n]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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
    cases b
    · simpa [bit0_eq_two_mul n]
    · 

Proof state:
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)

Next tactic:
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, factorial]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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
    cases b
    · simpa [bit0_eq_two_mul n]
    · suffices multiplicity 2 (2 * n + 1) + multiplicity 2 (2 * n)! < ↑(2 * n) + 1 by
        

Proof state:
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)

Next tactic:
simpa [succ_eq_add_one, multiplicity.mul, h2, prime_two, Nat.bit1_eq_succ_bit0,
          bit0_eq_two_mul n, factorial]
theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by
  have h2 := prime_two.prime
  refine' binaryRec _ _
  · exact fun h => False.elim <| h rfl
  · intro b n ih h
    by_cases hn : n = 0
    · subst hn
      simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h
      simp only [h, bit_true, bit1_zero, factorial, mul_one, Nat.isUnit_iff, cast_one]
      rw [Prime.multiplicity_one]
      simp only [zero_lt_one]
      decide
    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
    cases b
    · simpa [bit0_eq_two_mul n]
    · 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, factorial]
      

Proof state:
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

Next tactic:
rw [multiplicity_eq_zero.2 (two_not_dvd_two_mul_add_one n), zero_add]