l3lab/ntp-mathlib huggingface dataset:
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    

Proof state:
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
this : adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A'
⊢ adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A

Next tactic:
rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  

Proof state:
case succ.succ
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
⊢ adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A'

Next tactic:
have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by 

Proof state:
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
⊢ Fintype.card n - 2 + 1 = Fintype.card n - 1

Next tactic:
simp [h_card]
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
  

Proof state:
case succ.succ
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1
⊢ adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A'

Next tactic:
have is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A') := fun x y =>
    mul_left_cancel₀ (det_mvPolynomialX_ne_zero n ℤ)
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
  have is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A') := fun x y =>
    mul_left_cancel₀ (det_mvPolynomialX_ne_zero n ℤ)
  

Proof state:
case succ.succ
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1
is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A')
⊢ adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A'

Next tactic:
apply is_reg.matrix
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
  have is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A') := fun x y =>
    mul_left_cancel₀ (det_mvPolynomialX_ne_zero n ℤ)
  apply is_reg.matrix
  

Proof state:
case succ.succ.a
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1
is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A')
⊢ (fun x => det A' • x) (adjugate (adjugate A')) = (fun x => det A' • x) (det A' ^ (Fintype.card n - 2) • A')

Next tactic:
simp only
/-- Note that this is not true for `Fintype.card n = 1` since `1 - 2 = 0` and not `-1`. -/
theorem adjugate_adjugate (A : Matrix n n α) (h : Fintype.card n ≠ 1) :
    adjugate (adjugate A) = det A ^ (Fintype.card n - 2) • A := by
  -- get rid of the `- 2`
  cases' h_card : Fintype.card n with n'
  · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card
    apply Subsingleton.elim
  cases n'
  · exact (h h_card).elim
  rw [← h_card]
  -- express `A` as an evaluation of a polynomial in n^2 variables, and solve in the polynomial ring
  -- where `A'.det` is non-zero.
  let A' := mvPolynomialX n n ℤ
  suffices adjugate (adjugate A') = det A' ^ (Fintype.card n - 2) • A' by
    rw [← mvPolynomialX_mapMatrix_aeval ℤ A, ← AlgHom.map_adjugate, ← AlgHom.map_adjugate, this,
      ← AlgHom.map_det, ← AlgHom.map_pow, AlgHom.mapMatrix_apply, AlgHom.mapMatrix_apply,
      Matrix.map_smul' _ _ _ (_root_.map_mul _)]
  have h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1 := by simp [h_card]
  have is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A') := fun x y =>
    mul_left_cancel₀ (det_mvPolynomialX_ne_zero n ℤ)
  apply is_reg.matrix
  simp only
  

Proof state:
case succ.succ.a
m : Type u
n : Type v
α : Type w
inst✝⁴ : DecidableEq n
inst✝³ : Fintype n
inst✝² : DecidableEq m
inst✝¹ : Fintype m
inst✝ : CommRing α
A : Matrix n n α
h : Fintype.card n ≠ 1
n✝ : ℕ
h_card : Fintype.card n = Nat.succ (Nat.succ n✝)
A' : Matrix n n (MvPolynomial (n × n) ℤ) := mvPolynomialX n n ℤ
h_card' : Fintype.card n - 2 + 1 = Fintype.card n - 1
is_reg : IsSMulRegular (MvPolynomial (n × n) ℤ) (det A')
⊢ det (mvPolynomialX n n ℤ) • adjugate (adjugate (mvPolynomialX n n ℤ)) =
    det (mvPolynomialX n n ℤ) • det (mvPolynomialX n n ℤ) ^ (Fintype.card n - 2) • mvPolynomialX n n ℤ

Next tactic:
rw [smul_smul, ← pow_succ, h_card', det_smul_adjugate_adjugate]
@[simp]
theorem multinomial_nil : multinomial ∅ f = 1 := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
⊢ multinomial ∅ f = 1

Next tactic:
dsimp [multinomial]
@[simp]
theorem multinomial_nil : multinomial ∅ f = 1 := by
  dsimp [multinomial]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
⊢ 1 / 1 = 1

Next tactic:
rfl
@[simp]
theorem multinomial_singleton : multinomial {a} f = 1 := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
⊢ multinomial {a} f = 1

Next tactic:
simp [multinomial, Nat.div_self (factorial_pos (f a))]
@[simp]
theorem multinomial_insert_one [DecidableEq α] (h : a ∉ s) (h₁ : f a = 1) :
    multinomial (insert a s) f = (s.sum f).succ * multinomial s f := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
h₁ : f a = 1
⊢ multinomial (insert a s) f = succ (Finset.sum s f) * multinomial s f

Next tactic:
simp only [multinomial, one_mul, factorial]
@[simp]
theorem multinomial_insert_one [DecidableEq α] (h : a ∉ s) (h₁ : f a = 1) :
    multinomial (insert a s) f = (s.sum f).succ * multinomial s f := by
  simp only [multinomial, one_mul, factorial]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
h₁ : f a = 1
⊢ (∑ i in insert a s, f i)! / ∏ i in insert a s, (f i)! = succ (Finset.sum s f) * ((∑ i in s, f i)! / ∏ i in s, (f i)!)

Next tactic:
rw [Finset.sum_insert h, Finset.prod_insert h, h₁, add_comm, ← succ_eq_add_one, factorial_succ]
@[simp]
theorem multinomial_insert_one [DecidableEq α] (h : a ∉ s) (h₁ : f a = 1) :
    multinomial (insert a s) f = (s.sum f).succ * multinomial s f := by
  simp only [multinomial, one_mul, factorial]
  rw [Finset.sum_insert h, Finset.prod_insert h, h₁, add_comm, ← succ_eq_add_one, factorial_succ]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
h₁ : f a = 1
⊢ (∑ x in s, f x + 1) * (∑ x in s, f x)! / (1! * ∏ x in s, (f x)!) =
    succ (Finset.sum s f) * ((∑ i in s, f i)! / ∏ i in s, (f i)!)

Next tactic:
simp only [factorial_one, one_mul, Function.comp_apply, factorial, mul_one, ← one_eq_succ_zero]
@[simp]
theorem multinomial_insert_one [DecidableEq α] (h : a ∉ s) (h₁ : f a = 1) :
    multinomial (insert a s) f = (s.sum f).succ * multinomial s f := by
  simp only [multinomial, one_mul, factorial]
  rw [Finset.sum_insert h, Finset.prod_insert h, h₁, add_comm, ← succ_eq_add_one, factorial_succ]
  simp only [factorial_one, one_mul, Function.comp_apply, factorial, mul_one, ← one_eq_succ_zero]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
h₁ : f a = 1
⊢ (∑ x in s, f x + 1) * (∑ x in s, f x)! / ∏ x in s, (f x)! =
    succ (Finset.sum s f) * ((∑ x in s, f x)! / ∏ x in s, (f x)!)

Next tactic:
rw [Nat.mul_div_assoc _ (prod_factorial_dvd_factorial_sum _ _)]
theorem multinomial_insert [DecidableEq α] (h : a ∉ s) :
    multinomial (insert a s) f = (f a + s.sum f).choose (f a) * multinomial s f := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
⊢ multinomial (insert a s) f = choose (f a + Finset.sum s f) (f a) * multinomial s f

Next tactic:
rw [choose_eq_factorial_div_factorial (le.intro rfl)]
theorem multinomial_insert [DecidableEq α] (h : a ∉ s) :
    multinomial (insert a s) f = (f a + s.sum f).choose (f a) * multinomial s f := by
  rw [choose_eq_factorial_div_factorial (le.intro rfl)]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
⊢ multinomial (insert a s) f = (f a + Finset.sum s f)! / ((f a)! * (f a + Finset.sum s f - f a)!) * multinomial s f

Next tactic:
simp only [multinomial, Nat.add_sub_cancel_left, Finset.sum_insert h, Finset.prod_insert h,
    Function.comp_apply]
theorem multinomial_insert [DecidableEq α] (h : a ∉ s) :
    multinomial (insert a s) f = (f a + s.sum f).choose (f a) * multinomial s f := by
  rw [choose_eq_factorial_div_factorial (le.intro rfl)]
  simp only [multinomial, Nat.add_sub_cancel_left, Finset.sum_insert h, Finset.prod_insert h,
    Function.comp_apply]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ∉ s
⊢ (f a + ∑ i in s, f i)! / ((f a)! * ∏ i in s, (f i)!) =
    (f a + Finset.sum s f)! / ((f a)! * (Finset.sum s f)!) * ((∑ i in s, f i)! / ∏ i in s, (f i)!)

Next tactic:
rw [div_mul_div_comm ((f a).factorial_mul_factorial_dvd_factorial_add (s.sum f))
      (prod_factorial_dvd_factorial_sum _ _),
    mul_comm (f a)! (s.sum f)!, mul_assoc, mul_comm _ (s.sum f)!,
    Nat.mul_div_mul_left _ _ (factorial_pos _)]
theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) :
    multinomial s f = multinomial s g := by
  

Proof state:
α : Type u_1
s : Finset α
f✝ : α → ℕ
a b : α
n : ℕ
f g : α → ℕ
h : ∀ a ∈ s, f a = g a
⊢ multinomial s f = multinomial s g

Next tactic:
simp only [multinomial]
theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) :
    multinomial s f = multinomial s g := by
  simp only [multinomial]; 

Proof state:
α : Type u_1
s : Finset α
f✝ : α → ℕ
a b : α
n : ℕ
f g : α → ℕ
h : ∀ a ∈ s, f a = g a
⊢ (∑ i in s, f i)! / ∏ i in s, (f i)! = (∑ i in s, g i)! / ∏ i in s, (g i)!

Next tactic:
congr 1
theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) :
    multinomial s f = multinomial s g := by
  simp only [multinomial]; congr 1
  · 

Proof state:
case e_a
α : Type u_1
s : Finset α
f✝ : α → ℕ
a b : α
n : ℕ
f g : α → ℕ
h : ∀ a ∈ s, f a = g a
⊢ (∑ i in s, f i)! = (∑ i in s, g i)!

Next tactic:
rw [Finset.sum_congr rfl h]
theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) :
    multinomial s f = multinomial s g := by
  simp only [multinomial]; congr 1
  · rw [Finset.sum_congr rfl h]
  · 

Proof state:
case e_a
α : Type u_1
s : Finset α
f✝ : α → ℕ
a b : α
n : ℕ
f g : α → ℕ
h : ∀ a ∈ s, f a = g a
⊢ ∏ i in s, (f i)! = ∏ i in s, (g i)!

Next tactic:
exact Finset.prod_congr rfl fun a ha => by rw [h a ha]
theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) :
    multinomial s f = multinomial s g := by
  simp only [multinomial]; congr 1
  · rw [Finset.sum_congr rfl h]
  · exact Finset.prod_congr rfl fun a ha => by 

Proof state:
α : Type u_1
s : Finset α
f✝ : α → ℕ
a✝ b : α
n : ℕ
f g : α → ℕ
h : ∀ a ∈ s, f a = g a
a : α
ha : a ∈ s
⊢ (f a)! = (g a)!

Next tactic:
rw [h a ha]
theorem binomial_eq [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} f = (f a + f b)! / ((f a)! * (f b)!) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ multinomial {a, b} f = (f a + f b)! / ((f a)! * (f b)!)

Next tactic:
simp [multinomial, Finset.sum_pair h, Finset.prod_pair h]
theorem binomial_eq_choose [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} f = (f a + f b).choose (f a) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ multinomial {a, b} f = choose (f a + f b) (f a)

Next tactic:
simp [binomial_eq _ h, choose_eq_factorial_div_factorial (Nat.le_add_right _ _)]
theorem binomial_spec [DecidableEq α] (hab : a ≠ b) :
    (f a)! * (f b)! * multinomial {a, b} f = (f a + f b)! := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
hab : a ≠ b
⊢ (f a)! * (f b)! * multinomial {a, b} f = (f a + f b)!

Next tactic:
simpa [Finset.sum_pair hab, Finset.prod_pair hab] using multinomial_spec {a, b} f
@[simp]
theorem binomial_one [DecidableEq α] (h : a ≠ b) (h₁ : f a = 1) :
    multinomial {a, b} f = (f b).succ := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
h₁ : f a = 1
⊢ multinomial {a, b} f = succ (f b)

Next tactic:
simp [multinomial_insert_one {b} f (Finset.not_mem_singleton.mpr h) h₁]
theorem binomial_succ_succ [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} (Function.update (Function.update f a (f a).succ) b (f b).succ) =
      multinomial {a, b} (Function.update f a (f a).succ) +
      multinomial {a, b} (Function.update f b (f b).succ) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ multinomial {a, b} (Function.update (Function.update f a (succ (f a))) b (succ (f b))) =
    multinomial {a, b} (Function.update f a (succ (f a))) + multinomial {a, b} (Function.update f b (succ (f b)))

Next tactic:
simp only [binomial_eq_choose, Function.update_apply,
    h, Ne.def, ite_true, ite_false, not_false_eq_true]
theorem binomial_succ_succ [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} (Function.update (Function.update f a (f a).succ) b (f b).succ) =
      multinomial {a, b} (Function.update f a (f a).succ) +
      multinomial {a, b} (Function.update f b (f b).succ) := by
  simp only [binomial_eq_choose, Function.update_apply,
    h, Ne.def, ite_true, ite_false, not_false_eq_true]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ choose (succ (f a) + succ (f b)) (succ (f a)) =
    choose (succ (f a) + if b = a then succ (f a) else f b) (succ (f a)) + choose (f a + succ (f b)) (f a)

Next tactic:
rw [if_neg h.symm]
theorem binomial_succ_succ [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} (Function.update (Function.update f a (f a).succ) b (f b).succ) =
      multinomial {a, b} (Function.update f a (f a).succ) +
      multinomial {a, b} (Function.update f b (f b).succ) := by
  simp only [binomial_eq_choose, Function.update_apply,
    h, Ne.def, ite_true, ite_false, not_false_eq_true]
  rw [if_neg h.symm]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ choose (succ (f a) + succ (f b)) (succ (f a)) =
    choose (succ (f a) + f b) (succ (f a)) + choose (f a + succ (f b)) (f a)

Next tactic:
rw [add_succ, choose_succ_succ, succ_add_eq_add_succ]
theorem binomial_succ_succ [DecidableEq α] (h : a ≠ b) :
    multinomial {a, b} (Function.update (Function.update f a (f a).succ) b (f b).succ) =
      multinomial {a, b} (Function.update f a (f a).succ) +
      multinomial {a, b} (Function.update f b (f b).succ) := by
  simp only [binomial_eq_choose, Function.update_apply,
    h, Ne.def, ite_true, ite_false, not_false_eq_true]
  rw [if_neg h.symm]
  rw [add_succ, choose_succ_succ, succ_add_eq_add_succ]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ choose (f a + succ (f b)) (f a) + choose (f a + succ (f b)) (succ (f a)) =
    choose (f a + succ (f b)) (succ (f a)) + choose (f a + succ (f b)) (f a)

Next tactic:
ring
theorem succ_mul_binomial [DecidableEq α] (h : a ≠ b) :
    (f a + f b).succ * multinomial {a, b} f =
      (f a).succ * multinomial {a, b} (Function.update f a (f a).succ) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ succ (f a + f b) * multinomial {a, b} f = succ (f a) * multinomial {a, b} (Function.update f a (succ (f a)))

Next tactic:
rw [binomial_eq_choose _ h, binomial_eq_choose _ h, mul_comm (f a).succ, Function.update_same,
    Function.update_noteq (ne_comm.mp h)]
theorem succ_mul_binomial [DecidableEq α] (h : a ≠ b) :
    (f a + f b).succ * multinomial {a, b} f =
      (f a).succ * multinomial {a, b} (Function.update f a (f a).succ) := by
  rw [binomial_eq_choose _ h, binomial_eq_choose _ h, mul_comm (f a).succ, Function.update_same,
    Function.update_noteq (ne_comm.mp h)]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a b : α
n : ℕ
inst✝ : DecidableEq α
h : a ≠ b
⊢ succ (f a + f b) * choose (f a + f b) (f a) = choose (succ (f a) + f b) (succ (f a)) * succ (f a)

Next tactic:
rw [succ_mul_choose_eq (f a + f b) (f a), succ_add (f a) (f b)]
theorem multinomial_univ_two (a b : ℕ) :
    multinomial Finset.univ ![a, b] = (a + b)! / (a ! * b !) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a✝ b✝ : α
n a b : ℕ
⊢ multinomial Finset.univ ![a, b] = (a + b)! / (a ! * b !)

Next tactic:
rw [multinomial, Fin.sum_univ_two, Fin.prod_univ_two, Matrix.cons_val_zero, Matrix.cons_val_one,
    Matrix.head_cons]
theorem multinomial_univ_three (a b c : ℕ) :
    multinomial Finset.univ ![a, b, c] = (a + b + c)! / (a ! * b ! * c !) := by
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a✝ b✝ : α
n a b c : ℕ
⊢ multinomial Finset.univ ![a, b, c] = (a + b + c)! / (a ! * b ! * c !)

Next tactic:
rw [multinomial, Fin.sum_univ_three, Fin.prod_univ_three]
theorem multinomial_univ_three (a b c : ℕ) :
    multinomial Finset.univ ![a, b, c] = (a + b + c)! / (a ! * b ! * c !) := by
  rw [multinomial, Fin.sum_univ_three, Fin.prod_univ_three]
  

Proof state:
α : Type u_1
s : Finset α
f : α → ℕ
a✝ b✝ : α
n a b c : ℕ
⊢ (Matrix.vecCons a ![b, c] 0 + Matrix.vecCons a ![b, c] 1 + Matrix.vecCons a ![b, c] 2)! /
      ((Matrix.vecCons a ![b, c] 0)! * (Matrix.vecCons a ![b, c] 1)! * (Matrix.vecCons a ![b, c] 2)!) =
    (a + b + c)! / (a ! * b ! * c !)

Next tactic:
rfl
theorem multinomial_update (a : α) (f : α →₀ ℕ) :
    f.multinomial = (f.sum fun _ => id).choose (f a) * (f.update a 0).multinomial := by
  

Proof state:
α : Type u_1
a : α
f : α →₀ ℕ
⊢ multinomial f = choose (sum f fun x => id) (f a) * multinomial (update f a 0)

Next tactic:
simp only [multinomial_eq]