l3lab/ntp-mathlib huggingface dataset:
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      

Proof state:
case inl
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
⊢ choose (n + 1) (succ k) * (succ k)! * (n + 1 - succ k)! = (n + 1)!

Next tactic:
have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        

Proof state:
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
⊢ (n - k)! = (n - k) * (n - succ k)!

Next tactic:
rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      

Proof state:
case inl
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
h₁ : (n - k)! = (n - k) * (n - succ k)!
⊢ choose (n + 1) (succ k) * (succ k)! * (n + 1 - succ k)! = (n + 1)!

Next tactic:
have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        

Proof state:
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
h₁ : (n - k)! = (n - k) * (n - succ k)!
⊢ choose n (succ k) * (succ k)! * ((n - k) * (n - succ k)!) = (n - k) * n !

Next tactic:
rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        

Proof state:
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
h₁ : (n - k)! = (n - k) * (n - succ k)!
⊢ choose n (succ k) * (succ k)! * ((n - k) * (n - succ k)!) = (n - k) * (choose n (succ k) * (succ k)! * (n - succ k)!)

Next tactic:
simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      

Proof state:
case inl
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
h₁ : (n - k)! = (n - k) * (n - succ k)!
h₂ : choose n (succ k) * (succ k)! * ((n - k) * (n - succ k)!) = (n - k) * n !
⊢ choose (n + 1) (succ k) * (succ k)! * (n + 1 - succ k)! = (n + 1)!

Next tactic:
have h₃ : k * n ! ≤ n * n ! := Nat.mul_le_mul_right _ (le_of_succ_le_succ hk)
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₃ : k * n ! ≤ n * n ! := Nat.mul_le_mul_right _ (le_of_succ_le_succ hk)
      

Proof state:
case inl
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k < n + 1
h : choose n k * (succ k)! * (n - k)! = (k + 1) * n !
h₁ : (n - k)! = (n - k) * (n - succ k)!
h₂ : choose n (succ k) * (succ k)! * ((n - k) * (n - succ k)!) = (n - k) * n !
h₃ : k * n ! ≤ n * n !
⊢ choose (n + 1) (succ k) * (succ k)! * (n + 1 - succ k)! = (n + 1)!

Next tactic:
rw [choose_succ_succ, add_mul, add_mul, succ_sub_succ, h, h₁, h₂, add_mul, tsub_mul,
        factorial_succ, ← add_tsub_assoc_of_le h₃, add_assoc, ← add_mul, add_tsub_cancel_left,
        add_comm]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₃ : k * n ! ≤ n * n ! := Nat.mul_le_mul_right _ (le_of_succ_le_succ hk)
      rw [choose_succ_succ, add_mul, add_mul, succ_sub_succ, h, h₁, h₂, add_mul, tsub_mul,
        factorial_succ, ← add_tsub_assoc_of_le h₃, add_assoc, ← add_mul, add_tsub_cancel_left,
        add_comm]
    · 

Proof state:
case inr
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k = n + 1
⊢ choose (n + 1) (succ k) * (succ k)! * (n + 1 - succ k)! = (n + 1)!

Next tactic:
rw [hk₁]
theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * k ! * (n - k)! = n !
  | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk]
  | n + 1, 0, _ => by simp
  | n + 1, succ k, hk => by
    rcases lt_or_eq_of_le hk with hk₁ | hk₁
    · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₁ : (n - k)! = (n - k) * (n - k.succ)! := by
        rw [← succ_sub_succ, succ_sub (le_of_lt_succ hk₁), factorial_succ]
      have h₂ : choose n (succ k) * k.succ ! * ((n - k) * (n - k.succ)!) = (n - k) * n ! := by
        rw [← choose_mul_factorial_mul_factorial (le_of_lt_succ hk₁)]
        simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc]
      have h₃ : k * n ! ≤ n * n ! := Nat.mul_le_mul_right _ (le_of_succ_le_succ hk)
      rw [choose_succ_succ, add_mul, add_mul, succ_sub_succ, h, h₁, h₂, add_mul, tsub_mul,
        factorial_succ, ← add_tsub_assoc_of_le h₃, add_assoc, ← add_mul, add_tsub_cancel_left,
        add_comm]
    · rw [hk₁]; 

Proof state:
case inr
n k : ℕ
hk : succ k ≤ n + 1
hk₁ : succ k = n + 1
⊢ choose (n + 1) (n + 1) * (n + 1)! * (n + 1 - (n + 1))! = (n + 1)!

Next tactic:
simp [hk₁, mul_comm, choose, tsub_self]
theorem choose_mul {n k s : ℕ} (hkn : k ≤ n) (hsk : s ≤ k) :
    n.choose k * k.choose s = n.choose s * (n - s).choose (k - s) :=
  have h : (n - k)! * (k - s)! * s ! ≠ 0 := by 

Proof state:
n k s : ℕ
hkn : k ≤ n
hsk : s ≤ k
⊢ (n - k)! * (k - s)! * s ! ≠ 0

Next tactic:
apply_rules [factorial_ne_zero, mul_ne_zero]
theorem choose_mul {n k s : ℕ} (hkn : k ≤ n) (hsk : s ≤ k) :
    n.choose k * k.choose s = n.choose s * (n - s).choose (k - s) :=
  have h : (n - k)! * (k - s)! * s ! ≠ 0 := by apply_rules [factorial_ne_zero, mul_ne_zero]
  mul_right_cancel₀ h <|
  calc
    n.choose k * k.choose s * ((n - k)! * (k - s)! * s !) =
        n.choose k * (k.choose s * s ! * (k - s)!) * (n - k)! :=
      by 

Proof state:
n k s : ℕ
hkn : k ≤ n
hsk : s ≤ k
h : (n - k)! * (k - s)! * s ! ≠ 0
⊢ choose n k * choose k s * ((n - k)! * (k - s)! * s !) = choose n k * (choose k s * s ! * (k - s)!) * (n - k)!

Next tactic:
rw [mul_assoc, mul_assoc, mul_assoc, mul_assoc _ s !, mul_assoc, mul_comm (n - k)!,
        mul_comm s !]
theorem choose_mul {n k s : ℕ} (hkn : k ≤ n) (hsk : s ≤ k) :
    n.choose k * k.choose s = n.choose s * (n - s).choose (k - s) :=
  have h : (n - k)! * (k - s)! * s ! ≠ 0 := by apply_rules [factorial_ne_zero, mul_ne_zero]
  mul_right_cancel₀ h <|
  calc
    n.choose k * k.choose s * ((n - k)! * (k - s)! * s !) =
        n.choose k * (k.choose s * s ! * (k - s)!) * (n - k)! :=
      by rw [mul_assoc, mul_assoc, mul_assoc, mul_assoc _ s !, mul_assoc, mul_comm (n - k)!,
        mul_comm s !]
    _ = n ! :=
      by 

Proof state:
n k s : ℕ
hkn : k ≤ n
hsk : s ≤ k
h : (n - k)! * (k - s)! * s ! ≠ 0
⊢ choose n k * (choose k s * s ! * (k - s)!) * (n - k)! = n !

Next tactic:
rw [choose_mul_factorial_mul_factorial hsk, choose_mul_factorial_mul_factorial hkn]
theorem choose_mul {n k s : ℕ} (hkn : k ≤ n) (hsk : s ≤ k) :
    n.choose k * k.choose s = n.choose s * (n - s).choose (k - s) :=
  have h : (n - k)! * (k - s)! * s ! ≠ 0 := by apply_rules [factorial_ne_zero, mul_ne_zero]
  mul_right_cancel₀ h <|
  calc
    n.choose k * k.choose s * ((n - k)! * (k - s)! * s !) =
        n.choose k * (k.choose s * s ! * (k - s)!) * (n - k)! :=
      by rw [mul_assoc, mul_assoc, mul_assoc, mul_assoc _ s !, mul_assoc, mul_comm (n - k)!,
        mul_comm s !]
    _ = n ! :=
      by rw [choose_mul_factorial_mul_factorial hsk, choose_mul_factorial_mul_factorial hkn]
    _ = n.choose s * s ! * ((n - s).choose (k - s) * (k - s)! * (n - s - (k - s))!) :=
      by 

Proof state:
n k s : ℕ
hkn : k ≤ n
hsk : s ≤ k
h : (n - k)! * (k - s)! * s ! ≠ 0
⊢ n ! = choose n s * s ! * (choose (n - s) (k - s) * (k - s)! * (n - s - (k - s))!)

Next tactic:
rw [choose_mul_factorial_mul_factorial (tsub_le_tsub_right hkn _),
        choose_mul_factorial_mul_factorial (hsk.trans hkn)]
theorem choose_mul {n k s : ℕ} (hkn : k ≤ n) (hsk : s ≤ k) :
    n.choose k * k.choose s = n.choose s * (n - s).choose (k - s) :=
  have h : (n - k)! * (k - s)! * s ! ≠ 0 := by apply_rules [factorial_ne_zero, mul_ne_zero]
  mul_right_cancel₀ h <|
  calc
    n.choose k * k.choose s * ((n - k)! * (k - s)! * s !) =
        n.choose k * (k.choose s * s ! * (k - s)!) * (n - k)! :=
      by rw [mul_assoc, mul_assoc, mul_assoc, mul_assoc _ s !, mul_assoc, mul_comm (n - k)!,
        mul_comm s !]
    _ = n ! :=
      by rw [choose_mul_factorial_mul_factorial hsk, choose_mul_factorial_mul_factorial hkn]
    _ = n.choose s * s ! * ((n - s).choose (k - s) * (k - s)! * (n - s - (k - s))!) :=
      by rw [choose_mul_factorial_mul_factorial (tsub_le_tsub_right hkn _),
        choose_mul_factorial_mul_factorial (hsk.trans hkn)]
    _ = n.choose s * (n - s).choose (k - s) * ((n - k)! * (k - s)! * s !) :=
      by 

Proof state:
n k s : ℕ
hkn : k ≤ n
hsk : s ≤ k
h : (n - k)! * (k - s)! * s ! ≠ 0
⊢ choose n s * s ! * (choose (n - s) (k - s) * (k - s)! * (n - s - (k - s))!) =
    choose n s * choose (n - s) (k - s) * ((n - k)! * (k - s)! * s !)

Next tactic:
rw [tsub_tsub_tsub_cancel_right hsk, mul_assoc, mul_left_comm s !, mul_assoc,
        mul_comm (k - s)!, mul_comm s !, mul_right_comm, ← mul_assoc]
theorem choose_eq_factorial_div_factorial {n k : ℕ} (hk : k ≤ n) :
    choose n k = n ! / (k ! * (n - k)!) := by
  

Proof state:
n k : ℕ
hk : k ≤ n
⊢ choose n k = n ! / (k ! * (n - k)!)

Next tactic:
rw [← choose_mul_factorial_mul_factorial hk, mul_assoc]
theorem choose_eq_factorial_div_factorial {n k : ℕ} (hk : k ≤ n) :
    choose n k = n ! / (k ! * (n - k)!) := by
  rw [← choose_mul_factorial_mul_factorial hk, mul_assoc]
  

Proof state:
n k : ℕ
hk : k ≤ n
⊢ choose n k = choose n k * (k ! * (n - k)!) / (k ! * (n - k)!)

Next tactic:
exact (mul_div_left _ (mul_pos (factorial_pos _) (factorial_pos _))).symm
theorem add_choose (i j : ℕ) : (i + j).choose j = (i + j)! / (i ! * j !) := by
  

Proof state:
i j : ℕ
⊢ choose (i + j) j = (i + j)! / (i ! * j !)

Next tactic:
rw [choose_eq_factorial_div_factorial (Nat.le_add_left j i), add_tsub_cancel_right, mul_comm]
theorem add_choose_mul_factorial_mul_factorial (i j : ℕ) :
    (i + j).choose j * i ! * j ! = (i + j)! := by
  

Proof state:
i j : ℕ
⊢ choose (i + j) j * i ! * j ! = (i + j)!

Next tactic:
rw [← choose_mul_factorial_mul_factorial (Nat.le_add_left _ _), add_tsub_cancel_right,
    mul_right_comm]
theorem factorial_mul_factorial_dvd_factorial {n k : ℕ} (hk : k ≤ n) : k ! * (n - k)! ∣ n ! := by
  

Proof state:
n k : ℕ
hk : k ≤ n
⊢ k ! * (n - k)! ∣ n !

Next tactic:
rw [← choose_mul_factorial_mul_factorial hk, mul_assoc]
theorem factorial_mul_factorial_dvd_factorial {n k : ℕ} (hk : k ≤ n) : k ! * (n - k)! ∣ n ! := by
  rw [← choose_mul_factorial_mul_factorial hk, mul_assoc]; 

Proof state:
n k : ℕ
hk : k ≤ n
⊢ k ! * (n - k)! ∣ choose n k * (k ! * (n - k)!)

Next tactic:
exact dvd_mul_left _ _
theorem factorial_mul_factorial_dvd_factorial_add (i j : ℕ) : i ! * j ! ∣ (i + j)! := by
  

Proof state:
i j : ℕ
⊢ i ! * j ! ∣ (i + j)!

Next tactic:
suffices i ! * (i + j - i) ! ∣ (i + j)! by
    rwa [add_tsub_cancel_left i j] at this
theorem factorial_mul_factorial_dvd_factorial_add (i j : ℕ) : i ! * j ! ∣ (i + j)! := by
  suffices i ! * (i + j - i) ! ∣ (i + j)! by
    

Proof state:
i j : ℕ
this : i ! * (i + j - i)! ∣ (i + j)!
⊢ i ! * j ! ∣ (i + j)!

Next tactic:
rwa [add_tsub_cancel_left i j] at this
theorem factorial_mul_factorial_dvd_factorial_add (i j : ℕ) : i ! * j ! ∣ (i + j)! := by
  suffices i ! * (i + j - i) ! ∣ (i + j)! by
    rwa [add_tsub_cancel_left i j] at this
  

Proof state:
i j : ℕ
⊢ i ! * (i + j - i)! ∣ (i + j)!

Next tactic:
exact factorial_mul_factorial_dvd_factorial (Nat.le_add_right _ _)
@[simp]
theorem choose_symm {n k : ℕ} (hk : k ≤ n) : choose n (n - k) = choose n k := by
  

Proof state:
n k : ℕ
hk : k ≤ n
⊢ choose n (n - k) = choose n k

Next tactic:
rw [choose_eq_factorial_div_factorial hk, choose_eq_factorial_div_factorial (Nat.sub_le _ _),
    tsub_tsub_cancel_of_le hk, mul_comm]
theorem choose_symm_of_eq_add {n a b : ℕ} (h : n = a + b) : Nat.choose n a = Nat.choose n b := by
  

Proof state:
n a b : ℕ
h : n = a + b
⊢ choose n a = choose n b

Next tactic:
suffices choose n (n - b) = choose n b by
    rw [h, add_tsub_cancel_right] at this; rwa [h]
theorem choose_symm_of_eq_add {n a b : ℕ} (h : n = a + b) : Nat.choose n a = Nat.choose n b := by
  suffices choose n (n - b) = choose n b by
    

Proof state:
n a b : ℕ
h : n = a + b
this : choose n (n - b) = choose n b
⊢ choose n a = choose n b

Next tactic:
rw [h, add_tsub_cancel_right] at this
theorem choose_symm_of_eq_add {n a b : ℕ} (h : n = a + b) : Nat.choose n a = Nat.choose n b := by
  suffices choose n (n - b) = choose n b by
    rw [h, add_tsub_cancel_right] at this; 

Proof state:
n a b : ℕ
h : n = a + b
this : choose (a + b) a = choose (a + b) b
⊢ choose n a = choose n b

Next tactic:
rwa [h]
theorem choose_symm_of_eq_add {n a b : ℕ} (h : n = a + b) : Nat.choose n a = Nat.choose n b := by
  suffices choose n (n - b) = choose n b by
    rw [h, add_tsub_cancel_right] at this; rwa [h]
  

Proof state:
n a b : ℕ
h : n = a + b
⊢ choose n (n - b) = choose n b

Next tactic:
exact choose_symm (h ▸ le_add_left _ _)
theorem choose_symm_half (m : ℕ) : choose (2 * m + 1) (m + 1) = choose (2 * m + 1) m := by
  

Proof state:
m : ℕ
⊢ choose (2 * m + 1) (m + 1) = choose (2 * m + 1) m

Next tactic:
apply choose_symm_of_eq_add
theorem choose_symm_half (m : ℕ) : choose (2 * m + 1) (m + 1) = choose (2 * m + 1) m := by
  apply choose_symm_of_eq_add
  

Proof state:
case h
m : ℕ
⊢ 2 * m + 1 = m + 1 + m

Next tactic:
rw [add_comm m 1, add_assoc 1 m m, add_comm (2 * m) 1, two_mul m]
theorem choose_succ_right_eq (n k : ℕ) : choose n (k + 1) * (k + 1) = choose n k * (n - k) := by
  

Proof state:
n k : ℕ
⊢ choose n (k + 1) * (k + 1) = choose n k * (n - k)

Next tactic:
have e : (n + 1) * choose n k = choose n k * (k + 1) + choose n (k + 1) * (k + 1) := by
    rw [← right_distrib, ← choose_succ_succ, succ_mul_choose_eq]
theorem choose_succ_right_eq (n k : ℕ) : choose n (k + 1) * (k + 1) = choose n k * (n - k) := by
  have e : (n + 1) * choose n k = choose n k * (k + 1) + choose n (k + 1) * (k + 1) := by
    

Proof state:
n k : ℕ
⊢ (n + 1) * choose n k = choose n k * (k + 1) + choose n (k + 1) * (k + 1)

Next tactic:
rw [← right_distrib, ← choose_succ_succ, succ_mul_choose_eq]
theorem choose_succ_right_eq (n k : ℕ) : choose n (k + 1) * (k + 1) = choose n k * (n - k) := by
  have e : (n + 1) * choose n k = choose n k * (k + 1) + choose n (k + 1) * (k + 1) := by
    rw [← right_distrib, ← choose_succ_succ, succ_mul_choose_eq]
  

Proof state:
n k : ℕ
e : (n + 1) * choose n k = choose n k * (k + 1) + choose n (k + 1) * (k + 1)
⊢ choose n (k + 1) * (k + 1) = choose n k * (n - k)

Next tactic:
rw [← tsub_eq_of_eq_add_rev e, mul_comm, ← mul_tsub, add_tsub_add_eq_tsub_right]
@[simp]
theorem choose_succ_self_right : ∀ n : ℕ, (n + 1).choose n = n + 1
  | 0 => rfl
  | n + 1 => by 

Proof state:
n : ℕ
⊢ choose (n + 1 + 1) (n + 1) = n + 1 + 1

Next tactic:
rw [choose_succ_succ, choose_succ_self_right n, choose_self]
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  

Proof state:
n k : ℕ
⊢ choose n k * (n + 1) = choose (n + 1) k * (n + 1 - k)

Next tactic:
cases k with
  | zero => simp
  | succ k =>
    obtain hk | hk := le_or_lt (k + 1) (n + 1)
    · rw [choose_succ_succ, add_mul, succ_sub_succ, ← choose_succ_right_eq, ← succ_sub_succ,
        mul_tsub, add_tsub_cancel_of_le (Nat.mul_le_mul_left _ hk)]
    · rw [choose_eq_zero_of_lt hk, choose_eq_zero_of_lt (n.lt_succ_self.trans hk), zero_mul,
        zero_mul]
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  

Proof state:
case zero
n : ℕ
⊢ choose n zero * (n + 1) = choose (n + 1) zero * (n + 1 - zero)

Next tactic:
| zero => simp
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  | zero => 

Proof state:
case zero
n : ℕ
⊢ choose n zero * (n + 1) = choose (n + 1) zero * (n + 1 - zero)

Next tactic:
simp
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  | zero => simp
  

Proof state:
case succ
n k : ℕ
⊢ choose n (succ k) * (n + 1) = choose (n + 1) (succ k) * (n + 1 - succ k)

Next tactic:
| succ k =>
    obtain hk | hk := le_or_lt (k + 1) (n + 1)
    · rw [choose_succ_succ, add_mul, succ_sub_succ, ← choose_succ_right_eq, ← succ_sub_succ,
        mul_tsub, add_tsub_cancel_of_le (Nat.mul_le_mul_left _ hk)]
    · rw [choose_eq_zero_of_lt hk, choose_eq_zero_of_lt (n.lt_succ_self.trans hk), zero_mul,
        zero_mul]
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  | zero => simp
  | succ k =>
    

Proof state:
case succ
n k : ℕ
⊢ choose n (succ k) * (n + 1) = choose (n + 1) (succ k) * (n + 1 - succ k)

Next tactic:
obtain hk | hk := le_or_lt (k + 1) (n + 1)
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  | zero => simp
  | succ k =>
    obtain hk | hk := le_or_lt (k + 1) (n + 1)
    · 

Proof state:
case succ.inl
n k : ℕ
hk : k + 1 ≤ n + 1
⊢ choose n (succ k) * (n + 1) = choose (n + 1) (succ k) * (n + 1 - succ k)

Next tactic:
rw [choose_succ_succ, add_mul, succ_sub_succ, ← choose_succ_right_eq, ← succ_sub_succ,
        mul_tsub, add_tsub_cancel_of_le (Nat.mul_le_mul_left _ hk)]
theorem choose_mul_succ_eq (n k : ℕ) : n.choose k * (n + 1) = (n + 1).choose k * (n + 1 - k) := by
  cases k with
  | zero => simp
  | succ k =>
    obtain hk | hk := le_or_lt (k + 1) (n + 1)
    · rw [choose_succ_succ, add_mul, succ_sub_succ, ← choose_succ_right_eq, ← succ_sub_succ,
        mul_tsub, add_tsub_cancel_of_le (Nat.mul_le_mul_left _ hk)]
    · 

Proof state:
case succ.inr
n k : ℕ
hk : n + 1 < k + 1
⊢ choose n (succ k) * (n + 1) = choose (n + 1) (succ k) * (n + 1 - succ k)

Next tactic:
rw [choose_eq_zero_of_lt hk, choose_eq_zero_of_lt (n.lt_succ_self.trans hk), zero_mul,
        zero_mul]
theorem ascFactorial_eq_factorial_mul_choose (n k : ℕ) :
    n.ascFactorial k = k ! * (n + k).choose k := by
  

Proof state:
n k : ℕ
⊢ ascFactorial n k = k ! * choose (n + k) k

Next tactic:
rw [mul_comm]
theorem ascFactorial_eq_factorial_mul_choose (n k : ℕ) :
    n.ascFactorial k = k ! * (n + k).choose k := by
  rw [mul_comm]
  

Proof state:
n k : ℕ
⊢ ascFactorial n k = choose (n + k) k * k !

Next tactic:
apply mul_right_cancel₀ (factorial_ne_zero (n + k - k))
theorem ascFactorial_eq_factorial_mul_choose (n k : ℕ) :
    n.ascFactorial k = k ! * (n + k).choose k := by
  rw [mul_comm]
  apply mul_right_cancel₀ (factorial_ne_zero (n + k - k))
  

Proof state:
n k : ℕ
⊢ ascFactorial n k * (n + k - k)! = choose (n + k) k * k ! * (n + k - k)!

Next tactic:
rw [choose_mul_factorial_mul_factorial, add_tsub_cancel_right, ← factorial_mul_ascFactorial,
    mul_comm]
theorem ascFactorial_eq_factorial_mul_choose (n k : ℕ) :
    n.ascFactorial k = k ! * (n + k).choose k := by
  rw [mul_comm]
  apply mul_right_cancel₀ (factorial_ne_zero (n + k - k))
  rw [choose_mul_factorial_mul_factorial, add_tsub_cancel_right, ← factorial_mul_ascFactorial,
    mul_comm]
  

Proof state:
n k : ℕ
⊢ k ≤ n + k

Next tactic:
exact Nat.le_add_left k n