Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(data/sym/card): Prove stars and bars (superseded by #11162) #10846

Closed
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3fac454
feat(data/sym/card): Prove stars and bars
huynhtrankhanh Dec 16, 2021
9f6b414
incorporate suggestions
huynhtrankhanh Dec 17, 2021
5e9e42a
fix notation for sum and equiv
huynhtrankhanh Dec 17, 2021
37d6351
move sum parameter to the left
huynhtrankhanh Dec 17, 2021
524f951
remove a comma
huynhtrankhanh Dec 17, 2021
8f8907b
merge rewrites
huynhtrankhanh Dec 17, 2021
aea8073
use rcases
huynhtrankhanh Dec 17, 2021
c3f861d
use pattern matching
huynhtrankhanh Dec 17, 2021
6c2f7c4
break lines, merge two rewrites
huynhtrankhanh Dec 17, 2021
13be373
incorporate Kyle Miller's suggestions
huynhtrankhanh Dec 17, 2021
86a4334
define sym.map and prove lemmas about it. also provide two instances,…
huynhtrankhanh Dec 18, 2021
6e456d3
use sym.cons
huynhtrankhanh Dec 18, 2021
d6f9d66
provide instances for sym and sym2
huynhtrankhanh Dec 18, 2021
13a96c3
Merge branch 'leanprover-community:master' into master
huynhtrankhanh Dec 24, 2021
bdc5d3a
Merge branch 'leanprover-community:master' into master
huynhtrankhanh Dec 29, 2021
0ea8b9f
Use the sym API
huynhtrankhanh Dec 29, 2021
2d1b7e3
Tidy up proofs
huynhtrankhanh Dec 29, 2021
b5bde30
Golf sym.map_congr
huynhtrankhanh Dec 29, 2021
b2746c2
Use simpa to close a right_inv goal
huynhtrankhanh Dec 29, 2021
4a5971d
Move an argument in sym.map_congr
huynhtrankhanh Dec 29, 2021
22bdf78
Add docstring for sym.stars_and_bars
huynhtrankhanh Dec 29, 2021
6057a94
Change `lemma equivalent` to `def equivalent` and add docstrings
huynhtrankhanh Dec 30, 2021
11b9c25
Use subtype.ext in sym.map_congr
huynhtrankhanh Dec 30, 2021
653d124
Use fin.cast_succ
huynhtrankhanh Dec 30, 2021
6836823
Add a dot at the end of the sentence
huynhtrankhanh Dec 30, 2021
5106953
Use sym.erase
huynhtrankhanh Dec 30, 2021
f246759
Merge branch 'leanprover-community:master' into master
huynhtrankhanh Dec 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/data/sym/basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,14 @@ by simp [sym.map, subtype.mk.inj_eq]
(a :: s).map f = (f a) :: s.map f :=
by { cases s, simp [map, cons] }

@[congr] lemma map_congr {β : Type*} {f g : α → β} {s : sym α n} (h: ∀ x ∈ s, f x = g x) :
map f s = map g s :=
by simpa [map, subtype.mk.inj_eq] using multiset.map_congr h
huynhtrankhanh marked this conversation as resolved.
Show resolved Hide resolved

/-- Mapping an equivalence `α ≃ β` using `sym.map` gives an equivalence between `sym α n` and
`sym β n`. -/
@[simps]
def equiv_congr {β : Type u} (e : α ≃ β) : sym α n ≃ sym β n :=
def equiv_congr {α β : Type*} (e : α ≃ β) : sym α n ≃ sym β n :=
{ to_fun := map e,
inv_fun := map e.symm,
left_inv := λ x, by rw [map_map, equiv.symm_comp_self, map_id],
Expand Down
104 changes: 101 additions & 3 deletions src/data/sym/card.lean
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ In this file, we prove the case `n = 2` of stars and bars.

## Informal statement

If we have `n` objects to put in `k` boxes, we can do so in exactly `(n + k - 1).choose n` ways.
If we have `n` objects to put in `k` boxes, we can do so in exactly `(n + k - 1).choose k` ways.

## Formal statement

Expand All @@ -22,9 +22,8 @@ elements in those boxes corresponds to choosing how many of each element of `α`
of card `n`. `sym α n` being the subtype of `multiset α` of multisets of card `n`, writing stars
and bars using types gives
```lean
-- TODO: this lemma is not yet proven
lemma stars_and_bars {α : Type*} [fintype α] (n : ℕ) :
card (sym α n) = (card α + n - 1).choose (card α) := sorry
card (sym α n) = (card α + n - 1).choose n := sorry
```

## TODO
Expand All @@ -36,9 +35,108 @@ Prove the general case of stars and bars.
stars and bars
-/

def multichoose1 (n k : ℕ) := fintype.card (sym (fin n) k)

def multichoose2 (n k : ℕ) := (n + k - 1).choose k

def encode (n k : ℕ) (x : sym (fin n.succ) k.succ) : sym (fin n) k.succ ⊕ sym (fin n.succ) k :=
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make sense to generalize this to arbitrary types to have an Even More combinatorial proof:

def encode {k : ℕ} (v : α) (x : sym α k.succ) : sym {w // w ≠ v} k.succ ⊕ sym α k :=
if h : v ∈ x then
  sum.inr ⟨x.val.erase v, by { rw [multiset.card_erase_of_mem h, x.property], refl }⟩
else begin
  refine sum.inl ⟨x.val.attach.map (λ a, if h' : (a : α) = v then _ else _), _⟩,
  { rw ←h' at h,
    exact (h a.property).elim, },
  { use a, },
  { rw [multiset.card_map, multiset.card_attach, x.property], }
end

def decode {k : ℕ} (v : α) : sym {w // w ≠ v} k.succ ⊕ sym α k → sym α k.succ
| (sum.inl x) := ⟨x.val.map subtype.val, by simpa [multiset.card_map] using x.property⟩
| (sum.inr x) := sym.cons v x

There are some dependent type issues when trying to prove equivalent, though, because of attach. Maybe someone wants to figure it out?

lemma equivalent {k : ℕ} (v : α) : sym α k.succ ≃ sym {w // w ≠ v} k.succ ⊕ sym α k :=
{ to_fun := encode v,
  inv_fun := decode v,
  left_inv := sorry,
  right_inv := sorry }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the point in this generalization that you no longer have to start with fintype α? If so, I guess this does make sense.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eric-wieser The point is to show it doesn't depend on any properties of fin, and also that this might be a useful function beyond stars and bars. encode is "remove or restrict". decode might not need to exist on its own if there's sym.map since there ought to be a function sum a b -> (a -> c) -> (b -> c) -> c

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather write it like

def encode {k : ℕ} (x : sym (option α) k.succ) : sym α k.succ ⊕ sym (option α) k :=

and then use fintype.induction_empty_option. Subtypes are nasty.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@YaelDillies That seems good and more natural. (Mine was more like something in terms of nat.pred, which no one really wants if they can help it.)

if h : fin.last n ∈ x then
sum.inr ⟨x.val.erase (fin.last n), by { rw [multiset.card_erase_of_mem h, x.property], refl }⟩
huynhtrankhanh marked this conversation as resolved.
Show resolved Hide resolved
else begin
refine sum.inl (x.map (λ a, ⟨if (a : ℕ) = n then 0 else a, _⟩)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
refine sum.inl (x.map (λ a, ⟨if (a : ℕ) = n then 0 else a, _⟩)),
refine sum.inl (x.map fin.cast_pred),

{ split_ifs,
{ rw pos_iff_ne_zero,
rintro rfl,
obtain ⟨w, r⟩ := @multiset.exists_mem_of_ne_zero _ x.val (λ h, by simpa [h] using x.property),
simpa [subsingleton.elim w 0] using r, },
{ cases lt_or_eq_of_le (nat.le_of_lt_succ a.property); solve_by_elim } },
end

def decode (n k : ℕ) : sym (fin n) k.succ ⊕ sym (fin n.succ) k → sym (fin n.succ) k.succ
| (sum.inl x) := x.map (λ a, ⟨a.val, a.property.step⟩)
huynhtrankhanh marked this conversation as resolved.
Show resolved Hide resolved
| (sum.inr x) := (fin.last n)::x

lemma equivalent (n k : ℕ) : sym (fin n.succ) k.succ ≃ sym (fin n) k.succ ⊕ sym (fin n.succ) k :=
huynhtrankhanh marked this conversation as resolved.
Show resolved Hide resolved
{ to_fun := encode n k,
inv_fun := decode n k,
left_inv := λ x, begin
rw encode,
split_ifs,
{ cases x,
simpa [decode, sym.cons, sym.erase, subtype.mk.inj_eq] using multiset.cons_erase h },
{ simp only [decode, sym.map_map, subtype.mk.inj_eq, function.comp],
convert @sym.map_congr _ _ _ _ id _ _,
{ rw sym.map_id },
{ intros a h',
cases a,
split_ifs,
{ norm_num at h_1,
simp_rw h_1 at h',
exact (h h').elim },
{ norm_num } } },
end,
right_inv := begin
rintro (x|x),
{ cases x with x hx,
rw [decode, encode],
split_ifs,
{ obtain ⟨y, v, b⟩ := multiset.mem_map.mp h,
rw [fin.last, subtype.mk_eq_mk] at b,
have := y.property,
rw b at this,
exact nat.lt_asymm this this, },
{ simp only [sym.map_map, function.comp, fin.val_eq_coe, subtype.mk_eq_mk, fin.coe_mk],
convert sym.map_congr _,
{ rw multiset.map_id, },
{ rintros ⟨g, hg⟩ h',
split_ifs with h'',
{ simp only [fin.coe_mk] at h'',
subst g,
exact (nat.lt_asymm hg hg).elim, },
{ refl } } } },
{ rw [decode, encode],
split_ifs,
{ cases x, simp [sym.cons] },
{ apply h,
cases x,
simpa only [sym.cons] using multiset.mem_cons_self (fin.last n) x_val } }
end }

lemma multichoose1_rec (n k : ℕ) :
multichoose1 n.succ k.succ = multichoose1 n k.succ + multichoose1 n.succ k :=
by simpa only [multichoose1, fintype.card_sum.symm] using fintype.card_congr (equivalent n k)

lemma multichoose2_rec (n k : ℕ) :
multichoose2 n.succ k.succ = multichoose2 n k.succ + multichoose2 n.succ k :=
by simp [multichoose2, nat.choose_succ_succ, nat.add_comm, nat.add_succ]

lemma multichoose1_eq_multichoose2 : ∀ (n k : ℕ), multichoose1 n k = multichoose2 n k
| 0 0 := by simp [multichoose1, multichoose2]
| 0 (k + 1) := by simp [multichoose1, multichoose2, fintype.card]
| (n + 1) 0 := by simp [multichoose1, multichoose2]
| (n + 1) (k + 1) :=
by simp only [multichoose1_rec, multichoose2_rec, multichoose1_eq_multichoose2 n k.succ,
multichoose1_eq_multichoose2 n.succ k]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh what a nice short proof this was. Hopefully we can recover it somehow in the new version with some additional lemmas to help support manipulating equivalences and cardinalities.


open finset fintype

namespace sym

/-- The *stars and bars* lemma: the cardinality of `sym α n` is equal to
`(card α + n - 1) choose n`. -/
lemma stars_and_bars {α : Type*} [decidable_eq α] [fintype α] (n : ℕ) :
huynhtrankhanh marked this conversation as resolved.
Show resolved Hide resolved
fintype.card (sym α n) = (fintype.card α + n - 1).choose n :=
begin
have start := multichoose1_eq_multichoose2 (fintype.card α) n,
simp only [multichoose1, multichoose2] at start,
rw start.symm,
exact fintype.card_congr (equiv_congr ((@fintype.equiv_fin_of_card_eq α _ (fintype.card α) rfl))),
end

end sym

namespace sym2

variables {α : Type*} [decidable_eq α]

/-- The `diag` of `s : finset α` is sent on a finset of `sym2 α` of card `s.card`. -/
Expand Down