l3lab/ntp-mathlib huggingface dataset:
theorem choose_eq_asc_factorial_div_factorial (n k : ℕ) :
    (n + k).choose k = n.ascFactorial k / k ! := by
  

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

Next tactic:
apply mul_left_cancel₀ (factorial_ne_zero k)
theorem choose_eq_asc_factorial_div_factorial (n k : ℕ) :
    (n + k).choose k = n.ascFactorial k / k ! := by
  apply mul_left_cancel₀ (factorial_ne_zero k)
  

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

Next tactic:
rw [← ascFactorial_eq_factorial_mul_choose]
theorem choose_eq_asc_factorial_div_factorial (n k : ℕ) :
    (n + k).choose k = n.ascFactorial k / k ! := by
  apply mul_left_cancel₀ (factorial_ne_zero k)
  rw [← ascFactorial_eq_factorial_mul_choose]
  

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

Next tactic:
exact (Nat.mul_div_cancel' <| factorial_dvd_ascFactorial _ _).symm
theorem descFactorial_eq_factorial_mul_choose (n k : ℕ) : n.descFactorial k = k ! * n.choose k := by
  

Proof state:
n k : ℕ
⊢ descFactorial n k = k ! * choose n k

Next tactic:
obtain h | h := Nat.lt_or_ge n k
theorem descFactorial_eq_factorial_mul_choose (n k : ℕ) : n.descFactorial k = k ! * n.choose k := by
  obtain h | h := Nat.lt_or_ge n k
  · 

Proof state:
case inl
n k : ℕ
h : n < k
⊢ descFactorial n k = k ! * choose n k

Next tactic:
rw [descFactorial_eq_zero_iff_lt.2 h, choose_eq_zero_of_lt h, mul_zero]
theorem descFactorial_eq_factorial_mul_choose (n k : ℕ) : n.descFactorial k = k ! * n.choose k := by
  obtain h | h := Nat.lt_or_ge n k
  · rw [descFactorial_eq_zero_iff_lt.2 h, choose_eq_zero_of_lt h, mul_zero]
  

Proof state:
case inr
n k : ℕ
h : n ≥ k
⊢ descFactorial n k = k ! * choose n k

Next tactic:
rw [mul_comm]
theorem descFactorial_eq_factorial_mul_choose (n k : ℕ) : n.descFactorial k = k ! * n.choose k := by
  obtain h | h := Nat.lt_or_ge n k
  · rw [descFactorial_eq_zero_iff_lt.2 h, choose_eq_zero_of_lt h, mul_zero]
  rw [mul_comm]
  

Proof state:
case inr
n k : ℕ
h : n ≥ k
⊢ descFactorial n k = choose n k * k !

Next tactic:
apply mul_right_cancel₀ (factorial_ne_zero (n - k))
theorem descFactorial_eq_factorial_mul_choose (n k : ℕ) : n.descFactorial k = k ! * n.choose k := by
  obtain h | h := Nat.lt_or_ge n k
  · rw [descFactorial_eq_zero_iff_lt.2 h, choose_eq_zero_of_lt h, mul_zero]
  rw [mul_comm]
  apply mul_right_cancel₀ (factorial_ne_zero (n - k))
  

Proof state:
case inr
n k : ℕ
h : n ≥ k
⊢ descFactorial n k * (n - k)! = choose n k * k ! * (n - k)!

Next tactic:
rw [choose_mul_factorial_mul_factorial h, ← factorial_mul_descFactorial h, mul_comm]
theorem choose_eq_descFactorial_div_factorial (n k : ℕ) : n.choose k = n.descFactorial k / k ! := by
  

Proof state:
n k : ℕ
⊢ choose n k = descFactorial n k / k !

Next tactic:
apply mul_left_cancel₀ (factorial_ne_zero k)
theorem choose_eq_descFactorial_div_factorial (n k : ℕ) : n.choose k = n.descFactorial k / k ! := by
  apply mul_left_cancel₀ (factorial_ne_zero k)
  

Proof state:
n k : ℕ
⊢ k ! * choose n k = k ! * (descFactorial n k / k !)

Next tactic:
rw [← descFactorial_eq_factorial_mul_choose]
theorem choose_eq_descFactorial_div_factorial (n k : ℕ) : n.choose k = n.descFactorial k / k ! := by
  apply mul_left_cancel₀ (factorial_ne_zero k)
  rw [← descFactorial_eq_factorial_mul_choose]
  

Proof state:
n k : ℕ
⊢ descFactorial n k = k ! * (descFactorial n k / k !)

Next tactic:
exact (Nat.mul_div_cancel' <| factorial_dvd_descFactorial _ _).symm
/-- Show that `Nat.choose` is increasing for small values of the right argument. -/
theorem choose_le_succ_of_lt_half_left {r n : ℕ} (h : r < n / 2) :
    choose n r ≤ choose n (r + 1) := by
  

Proof state:
r n : ℕ
h : r < n / 2
⊢ choose n r ≤ choose n (r + 1)

Next tactic:
refine' le_of_mul_le_mul_right _ (lt_tsub_iff_left.mpr (lt_of_lt_of_le h (n.div_le_self 2)))
/-- Show that `Nat.choose` is increasing for small values of the right argument. -/
theorem choose_le_succ_of_lt_half_left {r n : ℕ} (h : r < n / 2) :
    choose n r ≤ choose n (r + 1) := by
  refine' le_of_mul_le_mul_right _ (lt_tsub_iff_left.mpr (lt_of_lt_of_le h (n.div_le_self 2)))
  

Proof state:
r n : ℕ
h : r < n / 2
⊢ choose n r * (n - r) ≤ choose n (r + 1) * (n - r)

Next tactic:
rw [← choose_succ_right_eq]
/-- Show that `Nat.choose` is increasing for small values of the right argument. -/
theorem choose_le_succ_of_lt_half_left {r n : ℕ} (h : r < n / 2) :
    choose n r ≤ choose n (r + 1) := by
  refine' le_of_mul_le_mul_right _ (lt_tsub_iff_left.mpr (lt_of_lt_of_le h (n.div_le_self 2)))
  rw [← choose_succ_right_eq]
  

Proof state:
r n : ℕ
h : r < n / 2
⊢ choose n (r + 1) * (r + 1) ≤ choose n (r + 1) * (n - r)

Next tactic:
apply Nat.mul_le_mul_left
/-- Show that `Nat.choose` is increasing for small values of the right argument. -/
theorem choose_le_succ_of_lt_half_left {r n : ℕ} (h : r < n / 2) :
    choose n r ≤ choose n (r + 1) := by
  refine' le_of_mul_le_mul_right _ (lt_tsub_iff_left.mpr (lt_of_lt_of_le h (n.div_le_self 2)))
  rw [← choose_succ_right_eq]
  apply Nat.mul_le_mul_left
  

Proof state:
case h
r n : ℕ
h : r < n / 2
⊢ r + 1 ≤ n - r

Next tactic:
rw [← Nat.lt_iff_add_one_le, lt_tsub_iff_left, ← mul_two]
/-- Show that `Nat.choose` is increasing for small values of the right argument. -/
theorem choose_le_succ_of_lt_half_left {r n : ℕ} (h : r < n / 2) :
    choose n r ≤ choose n (r + 1) := by
  refine' le_of_mul_le_mul_right _ (lt_tsub_iff_left.mpr (lt_of_lt_of_le h (n.div_le_self 2)))
  rw [← choose_succ_right_eq]
  apply Nat.mul_le_mul_left
  rw [← Nat.lt_iff_add_one_le, lt_tsub_iff_left, ← mul_two]
  

Proof state:
case h
r n : ℕ
h : r < n / 2
⊢ r * 2 < n

Next tactic:
exact lt_of_lt_of_le (mul_lt_mul_of_pos_right h zero_lt_two) (n.div_mul_le_self 2)
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  

Proof state:
r n : ℕ
⊢ choose n r ≤ choose n (n / 2)

Next tactic:
cases' le_or_gt r n with b b
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · 

Proof state:
case inl
r n : ℕ
b : r ≤ n
⊢ choose n r ≤ choose n (n / 2)

Next tactic:
rcases le_or_lt r (n / 2) with a | h
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · 

Proof state:
case inl.inl
r n : ℕ
b : r ≤ n
a : r ≤ n / 2
⊢ choose n r ≤ choose n (n / 2)

Next tactic:
apply choose_le_middle_of_le_half_left a
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · 

Proof state:
case inl.inr
r n : ℕ
b : r ≤ n
h : n / 2 < r
⊢ choose n r ≤ choose n (n / 2)

Next tactic:
rw [← choose_symm b]
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      

Proof state:
case inl.inr
r n : ℕ
b : r ≤ n
h : n / 2 < r
⊢ choose n (n - r) ≤ choose n (n / 2)

Next tactic:
apply choose_le_middle_of_le_half_left
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      apply choose_le_middle_of_le_half_left
      

Proof state:
case inl.inr.hr
r n : ℕ
b : r ≤ n
h : n / 2 < r
⊢ n - r ≤ n / 2

Next tactic:
rw [div_lt_iff_lt_mul' zero_lt_two] at h
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      apply choose_le_middle_of_le_half_left
      rw [div_lt_iff_lt_mul' zero_lt_two] at h
      

Proof state:
case inl.inr.hr
r n : ℕ
b : r ≤ n
h : n < r * 2
⊢ n - r ≤ n / 2

Next tactic:
rw [le_div_iff_mul_le' zero_lt_two, tsub_mul, tsub_le_iff_tsub_le, mul_two,
        add_tsub_cancel_right]
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      apply choose_le_middle_of_le_half_left
      rw [div_lt_iff_lt_mul' zero_lt_two] at h
      rw [le_div_iff_mul_le' zero_lt_two, tsub_mul, tsub_le_iff_tsub_le, mul_two,
        add_tsub_cancel_right]
      

Proof state:
case inl.inr.hr
r n : ℕ
b : r ≤ n
h : n < r * 2
⊢ n ≤ r * 2

Next tactic:
exact le_of_lt h
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      apply choose_le_middle_of_le_half_left
      rw [div_lt_iff_lt_mul' zero_lt_two] at h
      rw [le_div_iff_mul_le' zero_lt_two, tsub_mul, tsub_le_iff_tsub_le, mul_two,
        add_tsub_cancel_right]
      exact le_of_lt h
  · 

Proof state:
case inr
r n : ℕ
b : r > n
⊢ choose n r ≤ choose n (n / 2)

Next tactic:
rw [choose_eq_zero_of_lt b]
/-- `choose n r` is maximised when `r` is `n/2`. -/
theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by
  cases' le_or_gt r n with b b
  · rcases le_or_lt r (n / 2) with a | h
    · apply choose_le_middle_of_le_half_left a
    · rw [← choose_symm b]
      apply choose_le_middle_of_le_half_left
      rw [div_lt_iff_lt_mul' zero_lt_two] at h
      rw [le_div_iff_mul_le' zero_lt_two, tsub_mul, tsub_le_iff_tsub_le, mul_two,
        add_tsub_cancel_right]
      exact le_of_lt h
  · rw [choose_eq_zero_of_lt b]
    

Proof state:
case inr
r n : ℕ
b : r > n
⊢ 0 ≤ choose n (n / 2)

Next tactic:
apply zero_le
theorem choose_le_succ (a c : ℕ) : choose a c ≤ choose a.succ c := by
  

Proof state:
a c : ℕ
⊢ choose a c ≤ choose (succ a) c

Next tactic:
cases c
theorem choose_le_succ (a c : ℕ) : choose a c ≤ choose a.succ c := by
  cases c <;> 

Proof state:
case zero
a : ℕ
⊢ choose a zero ≤ choose (succ a) zero

Next tactic:
simp [Nat.choose_succ_succ]
theorem choose_le_succ (a c : ℕ) : choose a c ≤ choose a.succ c := by
  cases c <;> 

Proof state:
case succ
a n✝ : ℕ
⊢ choose a (succ n✝) ≤ choose (succ a) (succ n✝)

Next tactic:
simp [Nat.choose_succ_succ]
theorem choose_le_add (a b c : ℕ) : choose a c ≤ choose (a + b) c := by
  

Proof state:
a b c : ℕ
⊢ choose a c ≤ choose (a + b) c

Next tactic:
induction' b with b_n b_ih
theorem choose_le_add (a b c : ℕ) : choose a c ≤ choose (a + b) c := by
  induction' b with b_n b_ih
  · 

Proof state:
case zero
a c : ℕ
⊢ choose a c ≤ choose (a + zero) c

Next tactic:
simp
theorem choose_le_add (a b c : ℕ) : choose a c ≤ choose (a + b) c := by
  induction' b with b_n b_ih
  · simp
  

Proof state:
case succ
a c b_n : ℕ
b_ih : choose a c ≤ choose (a + b_n) c
⊢ choose a c ≤ choose (a + succ b_n) c

Next tactic:
exact le_trans b_ih (choose_le_succ (a + b_n) c)
@[simp]
theorem multichoose_zero_right (n : ℕ) : multichoose n 0 = 1 := by 

Proof state:
n : ℕ
⊢ multichoose n 0 = 1

Next tactic:
cases n
@[simp]
theorem multichoose_zero_right (n : ℕ) : multichoose n 0 = 1 := by cases n <;> 

Proof state:
case zero
⊢ multichoose zero 0 = 1

Next tactic:
simp [multichoose]
@[simp]
theorem multichoose_zero_right (n : ℕ) : multichoose n 0 = 1 := by cases n <;> 

Proof state:
case succ
n✝ : ℕ
⊢ multichoose (succ n✝) 0 = 1

Next tactic:
simp [multichoose]
@[simp]
theorem multichoose_zero_succ (k : ℕ) : multichoose 0 (k + 1) = 0 := by 

Proof state:
k : ℕ
⊢ multichoose 0 (k + 1) = 0

Next tactic:
simp [multichoose]
theorem multichoose_succ_succ (n k : ℕ) :
    multichoose (n + 1) (k + 1) = multichoose n (k + 1) + multichoose (n + 1) k := by
  

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

Next tactic:
simp [multichoose]
@[simp]
theorem multichoose_one (k : ℕ) : multichoose 1 k = 1 := by
  

Proof state:
k : ℕ
⊢ multichoose 1 k = 1

Next tactic:
induction' k with k IH
@[simp]
theorem multichoose_one (k : ℕ) : multichoose 1 k = 1 := by
  induction' k with k IH; · 

Proof state:
case zero
⊢ multichoose 1 zero = 1

Next tactic:
simp
@[simp]
theorem multichoose_one (k : ℕ) : multichoose 1 k = 1 := by
  induction' k with k IH; · simp
  

Proof state:
case succ
k : ℕ
IH : multichoose 1 k = 1
⊢ multichoose 1 (succ k) = 1

Next tactic:
simp [multichoose_succ_succ 0 k, IH]
@[simp]
theorem multichoose_two (k : ℕ) : multichoose 2 k = k + 1 := by
  

Proof state:
k : ℕ
⊢ multichoose 2 k = k + 1

Next tactic:
induction' k with k IH
@[simp]
theorem multichoose_two (k : ℕ) : multichoose 2 k = k + 1 := by
  induction' k with k IH; · 

Proof state:
case zero
⊢ multichoose 2 zero = zero + 1

Next tactic:
simp
@[simp]
theorem multichoose_two (k : ℕ) : multichoose 2 k = k + 1 := by
  induction' k with k IH; · simp
  

Proof state:
case succ
k : ℕ
IH : multichoose 2 k = k + 1
⊢ multichoose 2 (succ k) = succ k + 1

Next tactic:
rw [multichoose, IH]
@[simp]
theorem multichoose_two (k : ℕ) : multichoose 2 k = k + 1 := by
  induction' k with k IH; · simp
  rw [multichoose, IH]
  

Proof state:
case succ
k : ℕ
IH : multichoose 2 k = k + 1
⊢ multichoose 1 (k + 1) + (k + 1) = succ k + 1

Next tactic:
simp [add_comm, succ_eq_add_one]
@[simp]
theorem multichoose_one_right (n : ℕ) : multichoose n 1 = n := by
  

Proof state:
n : ℕ
⊢ multichoose n 1 = n

Next tactic:
induction' n with n IH
@[simp]
theorem multichoose_one_right (n : ℕ) : multichoose n 1 = n := by
  induction' n with n IH; · 

Proof state:
case zero
⊢ multichoose zero 1 = zero

Next tactic:
simp
@[simp]
theorem multichoose_one_right (n : ℕ) : multichoose n 1 = n := by
  induction' n with n IH; · simp
  

Proof state:
case succ
n : ℕ
IH : multichoose n 1 = n
⊢ multichoose (succ n) 1 = succ n

Next tactic:
simp [multichoose_succ_succ n 0, IH]
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by 

Proof state:
x✝ : ℕ
⊢ multichoose x✝ 0 = choose (x✝ + 0 - 1) 0

Next tactic:
simp
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by 

Proof state:
k : ℕ
⊢ multichoose 0 (k + 1) = choose (0 + (k + 1) - 1) (k + 1)

Next tactic:
simp
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    

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

Next tactic:
have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    

Proof state:
n k : ℕ
this : n + (k + 1) < n + 1 + (k + 1)
⊢ multichoose (n + 1) (k + 1) = choose (n + 1 + (k + 1) - 1) (k + 1)

Next tactic:
have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    

Proof state:
n k : ℕ
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ multichoose (n + 1) (k + 1) = choose (n + 1 + (k + 1) - 1) (k + 1)

Next tactic:
erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
    

Proof state:
n k : ℕ
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ multichoose (n + 1) k + multichoose n (k + 1) = choose (n + k) k + choose (n + k) (succ k)

Next tactic:
simp [multichoose_eq n (k+1), multichoose_eq (n+1) k]
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
    simp [multichoose_eq n (k+1), multichoose_eq (n+1) k]
  termination_by multichoose_eq a b => a + b
  decreasing_by 

Proof state:
n k : ℕ
x✝ :
  ∀ (y : (_ : ℕ) ×' ℕ),
    (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 y
        { fst := succ n, snd := succ k } →
      multichoose y.1 y.2 = choose (y.1 + y.2 - 1) y.2
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 { fst := n + 1, snd := k }
    { fst := succ n, snd := succ k }

Next tactic:
{ assumption }
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
    simp [multichoose_eq n (k+1), multichoose_eq (n+1) k]
  termination_by multichoose_eq a b => a + b
  decreasing_by { 

Proof state:
n k : ℕ
x✝ :
  ∀ (y : (_ : ℕ) ×' ℕ),
    (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 y
        { fst := succ n, snd := succ k } →
      multichoose y.1 y.2 = choose (y.1 + y.2 - 1) y.2
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 { fst := n + 1, snd := k }
    { fst := succ n, snd := succ k }

Next tactic:
assumption
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
    simp [multichoose_eq n (k+1), multichoose_eq (n+1) k]
  termination_by multichoose_eq a b => a + b
  decreasing_by 

Proof state:
n k : ℕ
x✝ :
  ∀ (y : (_ : ℕ) ×' ℕ),
    (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 y
        { fst := succ n, snd := succ k } →
      multichoose y.1 y.2 = choose (y.1 + y.2 - 1) y.2
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 { fst := n, snd := k + 1 }
    { fst := succ n, snd := succ k }

Next tactic:
{ assumption }
theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k
  | _, 0 => by simp
  | 0, k + 1 => by simp
  | n + 1, k + 1 => by
    have : n + (k + 1) < (n + 1) + (k + 1) := add_lt_add_right (Nat.lt_succ_self _) _
    have : (n + 1) + k < (n + 1) + (k + 1) := add_lt_add_left (Nat.lt_succ_self _) _
    erw [multichoose_succ_succ, add_comm, Nat.succ_add_sub_one, ← add_assoc, Nat.choose_succ_succ]
    simp [multichoose_eq n (k+1), multichoose_eq (n+1) k]
  termination_by multichoose_eq a b => a + b
  decreasing_by { 

Proof state:
n k : ℕ
x✝ :
  ∀ (y : (_ : ℕ) ×' ℕ),
    (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 y
        { fst := succ n, snd := succ k } →
      multichoose y.1 y.2 = choose (y.1 + y.2 - 1) y.2
this✝ : n + (k + 1) < n + 1 + (k + 1)
this : n + 1 + k < n + 1 + (k + 1)
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => a + snd) instWellFoundedRelation).1 { fst := n, snd := k + 1 }
    { fst := succ n, snd := succ k }

Next tactic:
assumption
theorem zero_opow' (a : Ordinal) : 0 ^ a = 1 - a := by 

Proof state:
a : Ordinal.{u_1}
⊢ 0 ^ a = 1 - a

Next tactic:
simp only [opow_def, if_true]
@[simp]
theorem zero_opow {a : Ordinal} (a0 : a ≠ 0) : (0 : Ordinal) ^ a = 0 := by
  

Proof state:
a : Ordinal.{u_1}
a0 : a ≠ 0
⊢ 0 ^ a = 0

Next tactic:
rwa [zero_opow', Ordinal.sub_eq_zero_iff_le, one_le_iff_ne_zero]
@[simp]
theorem opow_zero (a : Ordinal) : a ^ (0 : Ordinal) = 1 := by
  

Proof state:
a : Ordinal.{u_1}
⊢ a ^ 0 = 1

Next tactic:
by_cases h : a = 0
@[simp]
theorem opow_zero (a : Ordinal) : a ^ (0 : Ordinal) = 1 := by
  by_cases h : a = 0
  · 

Proof state:
case pos
a : Ordinal.{u_1}
h : a = 0
⊢ a ^ 0 = 1

Next tactic:
simp only [opow_def, if_pos h, sub_zero]
@[simp]
theorem opow_zero (a : Ordinal) : a ^ (0 : Ordinal) = 1 := by
  by_cases h : a = 0
  · simp only [opow_def, if_pos h, sub_zero]
  · 

Proof state:
case neg
a : Ordinal.{u_1}
h : ¬a = 0
⊢ a ^ 0 = 1

Next tactic:
simp only [opow_def, if_neg h, limitRecOn_zero]
@[simp]
theorem opow_succ (a b : Ordinal) : a ^ succ b = a ^ b * a :=
  if h : a = 0 then by 

Proof state:
a b : Ordinal.{u_1}
h : a = 0
⊢ a ^ succ b = a ^ b * a

Next tactic:
subst a
@[simp]
theorem opow_succ (a b : Ordinal) : a ^ succ b = a ^ b * a :=
  if h : a = 0 then by subst a; 

Proof state:
b : Ordinal.{u_1}
⊢ 0 ^ succ b = 0 ^ b * 0

Next tactic:
simp only [zero_opow (succ_ne_zero _), mul_zero]
@[simp]
theorem opow_succ (a b : Ordinal) : a ^ succ b = a ^ b * a :=
  if h : a = 0 then by subst a; simp only [zero_opow (succ_ne_zero _), mul_zero]
  else by 

Proof state:
a b : Ordinal.{u_1}
h : ¬a = 0
⊢ a ^ succ b = a ^ b * a

Next tactic:
simp only [opow_def, limitRecOn_succ, if_neg h]
theorem opow_limit {a b : Ordinal} (a0 : a ≠ 0) (h : IsLimit b) :
    a ^ b = bsup.{u, u} b fun c _ => a ^ c := by
  

Proof state:
a b : Ordinal.{u}
a0 : a ≠ 0
h : IsLimit b
⊢ a ^ b = bsup b fun c x => a ^ c

Next tactic:
simp only [opow_def, if_neg a0]
theorem opow_limit {a b : Ordinal} (a0 : a ≠ 0) (h : IsLimit b) :
    a ^ b = bsup.{u, u} b fun c _ => a ^ c := by
  simp only [opow_def, if_neg a0]; 

Proof state:
a b : Ordinal.{u}
a0 : a ≠ 0
h : IsLimit b
⊢ (limitRecOn b 1 (fun x IH => IH * a) fun b x => bsup b) =
    bsup b fun c x => limitRecOn c 1 (fun x IH => IH * a) fun b x => bsup b

Next tactic:
rw [limitRecOn_limit _ _ _ _ h]
theorem opow_le_of_limit {a b c : Ordinal} (a0 : a ≠ 0) (h : IsLimit b) :
    a ^ b ≤ c ↔ ∀ b' < b, a ^ b' ≤ c := by 

Proof state:
a b c : Ordinal.{u_1}
a0 : a ≠ 0
h : IsLimit b
⊢ a ^ b ≤ c ↔ ∀ b' < b, a ^ b' ≤ c

Next tactic:
rw [opow_limit a0 h, bsup_le_iff]
theorem lt_opow_of_limit {a b c : Ordinal} (b0 : b ≠ 0) (h : IsLimit c) :
    a < b ^ c ↔ ∃ c' < c, a < b ^ c' := by
  

Proof state:
a b c : Ordinal.{u_1}
b0 : b ≠ 0
h : IsLimit c
⊢ a < b ^ c ↔ ∃ c' < c, a < b ^ c'

Next tactic:
rw [← not_iff_not, not_exists]
theorem lt_opow_of_limit {a b c : Ordinal} (b0 : b ≠ 0) (h : IsLimit c) :
    a < b ^ c ↔ ∃ c' < c, a < b ^ c' := by
  rw [← not_iff_not, not_exists]; 

Proof state:
a b c : Ordinal.{u_1}
b0 : b ≠ 0
h : IsLimit c
⊢ ¬a < b ^ c ↔ ∀ (x : Ordinal.{u_1}), ¬(x < c ∧ a < b ^ x)

Next tactic:
simp only [not_lt, opow_le_of_limit b0 h, exists_prop, not_and]
@[simp]
theorem opow_one (a : Ordinal) : a ^ (1 : Ordinal) = a := by
  

Proof state:
a : Ordinal.{u_1}
⊢ a ^ 1 = a

Next tactic:
rw [← succ_zero, opow_succ]