77
88public import Mathlib.Algebra.Order.Antidiag.Pi
99public import Mathlib.Data.Finsupp.Multiset
10+ public import Mathlib.Data.List.ToFinsupp
1011public import Mathlib.Data.Nat.Choose.Sum
1112public import Mathlib.Data.Nat.Factorial.BigOperators
1213public import Mathlib.Data.Nat.Factorial.DoubleFactorial
13-
1414/-!
1515# Multinomial
1616
@@ -27,6 +27,29 @@ This file defines the multinomial coefficients and several small lemmas for mani
2727
2828- `Finset.sum_pow`: The expansion of `(s.sum x) ^ n` using multinomial coefficients
2929
30+ - `Multiset.multinomial`.
31+ Given a multiset `m` of natural numbers, `m.multinomial` is the
32+ multinomial coefficient defined by `(m.sum) ! / ∏ i ∈ m, m i !`.
33+
34+ This should not be confused with `m.countPerms` which
35+ is defined as `m.toFinsupp.multinomial`.
36+
37+ As an example, one has `Multiset.multinomial {1, 2, 2} = 30`,
38+ while `Multiset.countPerms {1, 2, 2} = 3`.
39+
40+ - `Multiset.multinomial_cons` proves that
41+ `(x ::ₘ m).multinomial = Nat.choose (x + m.sum) x * m.multinomial`
42+ - `Multiset.multinomial_add` proves that
43+ `(m + m').multinomial = Nat.choose (m + m').sum m.sum * m.multinomial * m'.multinomial`
44+
45+ ## Implementation note for `Multiset.multinomial`.
46+
47+ To avoid the definition of `Multiset.multinomial` as a quotient given above,
48+ we define it in terms of `Finsupp.multinomial`, via lists:
49+ If `m : Multiset ℕ` is the multiset associated with a list `l : List ℕ`,
50+ then `m.multinomial = l.toFinsupp.multinomial`.
51+ Then we prove its invariance under permutation.
52+
3053-/
3154
3255@[expose] public section
@@ -385,3 +408,97 @@ theorem Finsupp.multinomial_of_support_subset {σ : Type*} {d : σ →₀ ℕ} {
385408 rw [Nat.multinomial, Finsupp.multinomial,
386409 sum_of_support_subset _ h _ (by simp), prod_of_support_subset _ h _ (by simp)]
387410 simp
411+
412+ namespace List
413+
414+ open Nat
415+
416+ lemma toFinsupp_sum {α : Type *} [AddCommMonoid α] [DecidableEq α] (l : List α) :
417+ l.toFinsupp.sum (fun _ a ↦ a) = l.sum := by
418+ match l with
419+ | nil => simp
420+ | x :: l =>
421+ simp only [toFinsupp_cons_eq_single_add_embDomain, sum_cons]
422+ rw [Finsupp.sum_add_index (by simp) (by simp)]
423+ simp [Finsupp.sum_embDomain, l.toFinsupp_sum]
424+
425+ /-- The multinomial coefficients given by a list of natural numbers.
426+
427+ See also `Multiset.multinomial` -/
428+ abbrev multinomial (l : List ℕ) : ℕ := l.toFinsupp.multinomial
429+
430+ theorem multinomial_cons (x : ℕ) (l : List ℕ) :
431+ (x :: l).multinomial = Nat.choose (x + l.sum) x * l.multinomial := by
432+ simp only [multinomial]
433+ rw [Finsupp.multinomial_update 0 (x :: l).toFinsupp]
434+ congr 1
435+ · congr
436+ exact List.toFinsupp_sum (x :: l)
437+ let succEmb : ℕ ↪ ℕ := { toFun := Nat.succ, inj' := Nat.succ_injective }
438+ simp only [toFinsupp_cons_eq_single_add_embDomain, Finsupp.multinomial_eq]
439+ have : (Finsupp.single 0 x + l.toFinsupp.embDomain succEmb).update 0 0 =
440+ (l.toFinsupp.embDomain succEmb).update 0 0 := by
441+ ext i
442+ by_cases hi : i = 0
443+ · simp [hi]
444+ · simp [Finsupp.update_apply, if_neg hi, Finsupp.single_eq_of_ne hi]
445+ have h (x) : (l.toFinsupp.embDomain succEmb) (x + 1 ) = l[x]?.getD 0 := by
446+ rw [Finsupp.embDomain_apply, dif_pos ⟨x, by simp [succEmb]⟩]
447+ simp [succEmb]
448+ simp [succEmb, this, Nat.multinomial, h]
449+
450+ end List
451+
452+ namespace Multiset
453+
454+ /-- The `multinomial` coefficients on `Multiset ℕ`. -/
455+ def multinomial (m : Multiset ℕ) : ℕ := Quot.liftOn m List.multinomial <| fun l l' h ↦ by
456+ induction h with
457+ | nil => simp
458+ | @cons x l l' hl hl' => simp [List.multinomial_cons, hl', hl.sum_nat]
459+ | @swap x y l =>
460+ simp only [List.multinomial_cons, ← mul_assoc, List.sum_cons]
461+ rw [← Nat.choose_symm (Nat.le_add_right y _), add_tsub_cancel_left]
462+ rw [add_left_comm, Nat.choose_mul (Nat.le_add_right _ _), add_tsub_cancel_left]
463+ simp [← Nat.choose_symm (Nat.le_add_right _ _), add_tsub_cancel_left]
464+ | @trans l l' l'' h h' ih ih' => rw [ih, ih']
465+
466+ theorem multinomial_cons (x : ℕ) (m : Multiset ℕ) :
467+ (x ::ₘ m).multinomial = Nat.choose (x + m.sum) x * m.multinomial := by
468+ obtain ⟨l, rfl⟩ := Quotient.exists_rep m
469+ exact List.multinomial_cons x l
470+
471+ @[simp]
472+ theorem multinomial_zero : Multiset.multinomial 0 = 1 := rfl
473+
474+ @[simp]
475+ theorem multinomial_singleton (n : ℕ) :
476+ Multiset.multinomial {n} = 1 := by
477+ simp [← cons_zero, multinomial_cons]
478+
479+ theorem multinomial_add (m m' : Multiset ℕ) :
480+ (m + m').multinomial = Nat.choose (m + m').sum m.sum * m.multinomial * m'.multinomial := by
481+ induction m using Multiset.induction_on with
482+ | empty => simp
483+ | cons x m hind =>
484+ simp only [cons_add, sum_cons, sum_add, multinomial_cons, hind, ← mul_assoc]
485+ congr 2
486+ rw [← Nat.choose_symm (Nat.le_add_right _ _), add_tsub_cancel_left, eq_comm,
487+ Nat.choose_mul (Nat.le_add_right _ _), ← Nat.choose_symm (Nat.le_add_right x _)]
488+ simp [add_tsub_cancel_left]
489+
490+ theorem multinomial_nsmul (k : ℕ) (m : Multiset ℕ) :
491+ (k • m).multinomial = Nat.multinomial (Finset.range k) (fun _ ↦ m.sum) * m.multinomial ^ k := by
492+ induction k with
493+ | zero => simp
494+ | succ k hk =>
495+ rw [succ_nsmul', multinomial_add, hk, Finset.range_add_one,
496+ Nat.multinomial_insert (by simp), sum_add, sum_nsmul, pow_succ']
497+ simp [smul_eq_mul, Finset.sum_const, Finset.card_range]
498+ ring
499+
500+ theorem multinomial_nsmul_singleton (k n : ℕ) :
501+ (k • {n} : Multiset ℕ).multinomial = Nat.multinomial (Finset.range k) (fun _ ↦ n) := by
502+ simp [multinomial_nsmul]
503+
504+ end Multiset
0 commit comments