Zulip Chat Archive

Stream: Is there code for X?

Topic: Stars and bars


Oliver Nash (Mar 13 2024 at 15:09):

We don't seem to have this in Mathlib. I don't suppose someone has it elsewhere:

import Mathlib.Algebra.BigOperators.Basic
import Mathlib.Data.Sym.Basic

open BigOperators

def Sym.starsAndBarsEquiv (ι : Type*) [Fintype ι] (k : ) :
    Sym ι k  {P : ι   //  i, P i = k} :=
  sorry

Johan Commelin (Mar 13 2024 at 15:23):

$ rg -i "stars and bars"
Mathlib/Data/Finset/Sym.lean
113:/-- Finset **stars and bars** for the case `n = 2`. -/

Mathlib/Data/Sym/Card.lean
14:# Stars and bars
20:this is central to the "stars and bars" technique in combinatorics, where we switch between
32:The "stars and bars" technique arises from another way of presenting the same problem. Instead of
47:while the "stars and bars" technique gives
53:stars and bars, multichoose
117:/-- The *stars and bars* lemma: the cardinality of `Sym α k` is equal to
191:/-- Type **stars and bars** for the case `n = 2`. -/

Mathlib/Data/Nat/Choose/Basic.lean
33:This is central to the "stars and bars" technique in informal mathematics, where we switch between
39:binomial coefficient, combination, multicombination, stars and bars

Johan Commelin (Mar 13 2024 at 15:24):

So I think it is there in some form.

Oliver Nash (Mar 13 2024 at 15:25):

Thanks, I did a similar search. IIUC, the results we have compute the cardinality of Sym ι k in terms of binomial coefficients, but do not provide the bijection I request.

Oliver Nash (Mar 13 2024 at 15:26):

Of course, I'd love to be corrected!

Johan Commelin (Mar 13 2024 at 15:32):

Ooh, I see. That's sad. Hopefully it is easy to refactor the proofs to get the equiv?

Oliver Nash (Mar 13 2024 at 15:32):

I'll take a look later this afternoon if I hear nothing else here.

Oliver Nash (Mar 13 2024 at 15:46):

OK I caved in and did it by hand:

import Mathlib.Algebra.BigOperators.Basic
import Mathlib.Data.Sym.Basic

open BigOperators

@[simp]
lemma Multiset.sum_count_eq_card {α : Type*} [Fintype α] [DecidableEq α] (s : Multiset α) :
     a, s.count a = Multiset.card s := by
  rw [ Multiset.toFinset_sum_count_eq,  Finset.sum_filter_ne_zero]
  congr
  ext
  simp

/-- A classic "stars and bars" bijection. -/
def Sym.starsAndBarsEquiv (ι : Type*) [DecidableEq ι] [Fintype ι] (k : ) :
    Sym ι k  {P : ι   //  i, P i = k} where
  toFun := fun s, hs  s.count, by simp [ hs]⟩
  invFun := fun P, hP   i, (P i)  ({i} : Multiset ι), by simpa
  left_inv := by
    rintro s, hs
    simp only
    congr
    ext i
    erw [Multiset.count_sum] -- TODO Fix
    simp [Multiset.count_singleton]
  right_inv := by
    rintro P, hP
    ext i
    simp only
    erw [Multiset.count_sum] -- TODO Fix
    simp [Multiset.count_singleton]

I now need to divert my attention but I'll PR this later today unless I hear a reason not to do so.

Eric Wieser (Mar 13 2024 at 15:53):

I think I discussed something similar in a DM with @Kyle Miller long ago

Eric Wieser (Mar 13 2024 at 15:54):

This shouldn't need finiteness, should it?

Junyan Xu (Mar 13 2024 at 15:56):

This also came up here in the complete homogeneous symmetric polynomial PR and I suggested constructing the Equiv but it was not actually done.

Junyan Xu (Mar 13 2024 at 16:02):

Eric Wieser said:

This shouldn't need finiteness, should it?

You can't write ∑ i, without ι being a Fintype. But you might use docs#Finsupp.sum. In fact there is docs#Multiset.toFinsupp. Maybe we should combine docs#Equiv.image with it to construct starsAndBarsEquiv.

Kyle Miller (Mar 13 2024 at 16:56):

@Oliver Nash That should be in mathlib. Having a version without Fintype seems like a separate project — having {P : ι → ℕ // ∑ i, P i = k} in bijective correspondence to some type with a know cardinality is important.

I wouldn't call this stars-and-bars however. This bijection is the observation that multisets are determined — and described by — finitely supported Nat-valued functions, via Multiset.count (which, by the way, seems to be missing results about how fun m => m.count is injective, and how the image of m.count is finite). Where are the stars and where are the bars?

Kyle Miller (Mar 13 2024 at 16:58):

I see, docs#Multiset.toFinsupp would be great for creating this equivalence. (And injectivity/finiteness facts about Multiset.count would be nice to factor out of it.)

Oliver Nash (Mar 13 2024 at 16:59):

Agreed, I shouldn't really call this "stars and bars". Fiddling with this now we can have the Finsupp version too if we do something like:

lemma Multiset.foo (ι : Type*) [DecidableEq ι] (k : ) :
    toFinsupp.toEquiv '' {s | Multiset.card s = k} = {P : ι →₀  | P.sum (fun _  id) = k} := by
  ext P
  simp only [AddEquiv.toEquiv_eq_coe, EquivLike.coe_coe, mem_image, mem_setOf_eq]
  refine ?_, ?_
  · rintro s, rfl, rfl
    simp [ Finsupp.card_toMultiset]
  · rintro rfl
    exact Multiset.toFinsupp.symm P, by simp [ Finsupp.card_toMultiset], by simp

def Sym.starsAndBarsEquiv' (ι : Type*) [DecidableEq ι] (k : ) :
    Sym ι k  {P : ι →₀  // P.sum (fun _  id) = k} :=
  (Multiset.toFinsupp.toEquiv.image _).trans <| Equiv.Set.ofEq <| Multiset.foo ι k

Junyan Xu (Mar 13 2024 at 17:08):

We also have docs#Finsupp.equivFunOnFinite to convert to the Fintype.sum version.

Oliver Nash (Mar 13 2024 at 17:42):

OK I'll PR something along these lines after dinner:

import Mathlib.Algebra.BigOperators.Basic
import Mathlib.Data.Finsupp.Multiset
import Mathlib.Data.Sym.Basic

open BigOperators

-- No longer need this lemma but still worth adding
@[simp]
lemma Multiset.sum_count_eq_card {α : Type*} [Fintype α] [DecidableEq α] (s : Multiset α) :
     a, s.count a = Multiset.card s := by
  rw [ Multiset.toFinset_sum_count_eq,  Finset.sum_filter_ne_zero]
  congr
  ext
  simp

attribute [simp] Finsupp.card_toMultiset

@[simp]
lemma Multiset.toFinsupp_sum_eq {ι : Type*} [DecidableEq ι] (s : Multiset ι) :
    s.toFinsupp.sum (fun _  id) = Multiset.card s := by
  rw [ Finsupp.card_toMultiset, toFinsupp_toMultiset]

lemma Multiset.toFinsupp_image_card_eq (ι : Type*) [DecidableEq ι] (k : ) :
    toFinsupp '' {s | Multiset.card s = k} = {P : ι →₀  | P.sum (fun _  id) = k} := by
  ext P
  refine ?_, ?_
  · rintro s, rfl, rfl
    simp
  · rintro rfl
    exact Multiset.toFinsupp.symm P, by simp, by simp

def Sym.equivNatSum (ι : Type*) [DecidableEq ι] (k : ) :
    Sym ι k  {P : ι →₀  // P.sum (fun _  id) = k} :=
  (Multiset.toFinsupp.toEquiv.image _).trans <| Equiv.Set.ofEq <|
    Multiset.toFinsupp_image_card_eq ι k

-- It is `Finsupp.equivFunOnFinite` that makes this noncomputable.
noncomputable def Sym.equivNatSum' (ι : Type*) [DecidableEq ι] [Fintype ι] (k : ) :
    Sym ι k  {P : ι   //  i, P i = k} :=
  (Sym.equivNatSum ι k).trans <| (Finsupp.equivFunOnFinite.image _).trans <| Equiv.Set.ofEq (by
    ext P
    refine ?_, ?_
    · rintro Q, rfl, rfl
      simp [Set.mem_def, Finsupp.sum_fintype]
    · rintro rfl
      exact Finsupp.equivFunOnFinite.symm P, by simp [Set.mem_def, Finsupp.sum_fintype], by simp⟩)

Oliver Nash (Mar 13 2024 at 20:19):

#11360

Eric Wieser (Mar 13 2024 at 20:28):

It seems pretty silly to me that this is noncomputable... will comment in the PR

Oliver Nash (Mar 14 2024 at 18:06):

Follow-up PR #11380 (in which stars and bars really do make an appearance).


Last updated: May 02 2025 at 03:31 UTC