Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 5cbfddd

Browse files
committed
feat(data/finset/sym): Symmetric powers of a finset (#11142)
This defines `finset.sym` and `finset.sym2`, which are the `finset` analogs of `sym` and `sym2`, in a new file `data.finset.sym`.
1 parent a8d37c1 commit 5cbfddd

File tree

6 files changed

+219
-13
lines changed

6 files changed

+219
-13
lines changed

src/data/finset/basic.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,6 +2545,10 @@ lemma disjoint_filter_filter {s t : finset α} {p q : α → Prop} [decidable_pr
25452545
(disjoint s t) → disjoint (s.filter p) (t.filter q) :=
25462546
disjoint.mono (filter_subset _ _) (filter_subset _ _)
25472547

2548+
lemma disjoint_filter_filter_neg (s : finset α) (p : α → Prop) [decidable_pred p] :
2549+
disjoint (s.filter p) (s.filter $ λ a, ¬ p a) :=
2550+
(disjoint_filter.2 $ λ a _, id).symm
2551+
25482552
lemma disjoint_iff_disjoint_coe {α : Type*} {a b : finset α} [decidable_eq α] :
25492553
disjoint a b ↔ disjoint (↑a : set α) (↑b : set α) :=
25502554
by { rw [finset.disjoint_left, set.disjoint_left], refl }

src/data/finset/prod.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ let ⟨xy, hxy⟩ := h in ⟨xy.2, (mem_product.1 hxy).2⟩
110110
@[simp] lemma nonempty_product : (s.product t).nonempty ↔ s.nonempty ∧ t.nonempty :=
111111
⟨λ h, ⟨h.fst, h.snd⟩, λ h, h.1.product h.2
112112

113+
@[simp] lemma product_eq_empty {s : finset α} {t : finset β} : s.product t = ∅ ↔ s = ∅ ∨ t = ∅ :=
114+
by rw [←not_nonempty_iff_eq_empty, nonempty_product, not_and_distrib, not_nonempty_iff_eq_empty,
115+
not_nonempty_iff_eq_empty]
116+
113117
@[simp] lemma singleton_product {a : α} :
114118
({a} : finset α).product t = t.map ⟨prod.mk a, prod.mk.inj_left _⟩ :=
115119
by { ext ⟨x, y⟩, simp [and.left_comm, eq_comm] }
@@ -172,5 +176,10 @@ end
172176

173177
@[simp] lemma off_diag_empty : (∅ : finset α).off_diag = ∅ := rfl
174178

179+
@[simp] lemma diag_union_off_diag : s.diag ∪ s.off_diag = s.product s :=
180+
filter_union_filter_neg_eq _ _
181+
182+
@[simp] lemma disjoint_diag_off_diag : disjoint s.diag s.off_diag := disjoint_filter_filter_neg _ _
183+
175184
end diag
176185
end finset

src/data/finset/sym.lean

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/-
2+
Copyright (c) 2021 Yaël Dillies. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Yaël Dillies
5+
-/
6+
import data.finset.prod
7+
import data.sym.sym2
8+
9+
/-!
10+
# Symmetric powers of a finset
11+
12+
This file defines the symmetric powers of a finset as `finset (sym α n)` and `finset (sym2 α)`.
13+
14+
## Main declarations
15+
16+
* `finset.sym`: The symmetric power of a finset. `s.sym n` is all the multisets of cardinality `n`
17+
whose elements are in `s`.
18+
* `finset.sym2`: The symmetric square of a finset. `s.sym2` is all the pairs whose elements are in
19+
`s`.
20+
21+
## TODO
22+
23+
`finset.sym` forms a Galois connection between `finset α` and `finset (sym α n)`. Similar for
24+
`finset.sym2`.
25+
-/
26+
27+
namespace finset
28+
variables {α : Type*} [decidable_eq α] {s t : finset α} {a b : α}
29+
30+
lemma is_diag_mk_of_mem_diag {a : α × α} (h : a ∈ s.diag) : sym2.is_diag ⟦a⟧ :=
31+
(sym2.is_diag_iff_proj_eq _).2 ((mem_diag _ _).1 h).2
32+
33+
lemma not_is_diag_mk_of_mem_off_diag {a : α × α} (h : a ∈ s.off_diag) : ¬ sym2.is_diag ⟦a⟧ :=
34+
by { rw sym2.is_diag_iff_proj_eq, exact ((mem_off_diag _ _).1 h).2.2 }
35+
36+
section sym2
37+
variables {m : sym2 α}
38+
39+
/-- Lifts a finset to `sym2 α`. `s.sym2` is the finset of all pairs with elements in `s`. -/
40+
protected def sym2 (s : finset α) : finset (sym2 α) := (s.product s).image quotient.mk
41+
42+
@[simp] lemma mem_sym2_iff : m ∈ s.sym2 ↔ ∀ a ∈ m, a ∈ s :=
43+
begin
44+
refine mem_image.trans
45+
⟨_, λ h, ⟨m.out, mem_product.2 ⟨h _ m.out_fst_mem, h _ m.out_snd_mem⟩, m.out_eq⟩⟩,
46+
rintro ⟨⟨a, b⟩, h, rfl⟩,
47+
rw sym2.ball,
48+
rwa mem_product at h,
49+
end
50+
51+
lemma mk_mem_sym2_iff : ⟦(a, b)⟧ ∈ s.sym2 ↔ a ∈ s ∧ b ∈ s := by rw [mem_sym2_iff, sym2.ball]
52+
53+
@[simp] lemma sym2_empty : (∅ : finset α).sym2 = ∅ := rfl
54+
55+
@[simp] lemma sym2_eq_empty : s.sym2 = ∅ ↔ s = ∅ :=
56+
by rw [finset.sym2, image_eq_empty, product_eq_empty, or_self]
57+
58+
@[simp] lemma sym2_nonempty : s.sym2.nonempty ↔ s.nonempty :=
59+
by rw [finset.sym2, nonempty.image_iff, nonempty_product, and_self]
60+
61+
alias sym2_nonempty ↔ _ finset.nonempty.sym2
62+
63+
attribute [protected] finset.nonempty.sym2
64+
65+
@[simp] lemma sym2_univ [fintype α] : (univ : finset α).sym2 = univ := rfl
66+
67+
@[simp] lemma sym2_singleton (a : α) : ({a} : finset α).sym2 = {sym2.diag a} :=
68+
by rw [finset.sym2, singleton_product_singleton, image_singleton, sym2.diag]
69+
70+
@[simp] lemma diag_mem_sym2_iff : sym2.diag a ∈ s.sym2 ↔ a ∈ s := mk_mem_sym2_iff.trans $ and_self _
71+
72+
@[simp] lemma sym2_mono (h : s ⊆ t) : s.sym2 ⊆ t.sym2 :=
73+
λ m he, mem_sym2_iff.2 $ λ a ha, h $ mem_sym2_iff.1 he _ ha
74+
75+
lemma image_diag_union_image_off_diag :
76+
s.diag.image quotient.mk ∪ s.off_diag.image quotient.mk = s.sym2 :=
77+
by { rw [←image_union, diag_union_off_diag], refl }
78+
79+
end sym2
80+
81+
section sym
82+
variables {n : ℕ} {m : sym α n}
83+
84+
/-- Lifts a finset to `sym α n`. `s.sym n` is the finset of all unordered tuples of cardinality `n`
85+
with elements in `s`. -/
86+
protected def sym (s : finset α) : Π n, finset (sym α n)
87+
| 0 := {∅}
88+
| (n + 1) := s.sup $ λ a, (sym n).image $ _root_.sym.cons a
89+
90+
@[simp] lemma sym_zero : s.sym 0 = {∅} := rfl
91+
@[simp] lemma sym_succ : s.sym (n + 1) = s.sup (λ a, (s.sym n).image $ sym.cons a) := rfl
92+
93+
@[simp] lemma mem_sym_iff : m ∈ s.sym n ↔ ∀ a ∈ m, a ∈ s :=
94+
begin
95+
induction n with n ih,
96+
{ refine mem_singleton.trans ⟨_, λ _, sym.eq_nil_of_card_zero _⟩,
97+
rintro rfl,
98+
exact λ a ha, ha.elim },
99+
refine mem_sup.trans ⟨_, λ h, _⟩,
100+
{ rintro ⟨a, ha, he⟩ b hb,
101+
rw mem_image at he,
102+
obtain ⟨m, he, rfl⟩ := he,
103+
rw sym.mem_cons at hb,
104+
obtain rfl | hb := hb,
105+
{ exact ha },
106+
{ exact ih.1 he _ hb } },
107+
{ obtain ⟨a, m, rfl⟩ := m.exists_eq_cons_of_succ,
108+
exact ⟨a, h _ $ sym.mem_cons_self _ _,
109+
mem_image_of_mem _ $ ih.2 $ λ b hb, h _ $ sym.mem_cons_of_mem hb⟩ }
110+
end
111+
112+
@[simp] lemma sym_empty (n : ℕ) : (∅ : finset α).sym (n + 1) = ∅ := rfl
113+
114+
lemma repeat_mem_sym (ha : a ∈ s) (n : ℕ) : sym.repeat a n ∈ s.sym n :=
115+
mem_sym_iff.2 $ λ b hb, by rwa (sym.mem_repeat.1 hb).2
116+
117+
protected lemma nonempty.sym (h : s.nonempty) (n : ℕ) : (s.sym n).nonempty :=
118+
let ⟨a, ha⟩ := h in ⟨_, repeat_mem_sym ha n⟩
119+
120+
@[simp] lemma sym_singleton (a : α) (n : ℕ) : ({a} : finset α).sym n = {sym.repeat a n} :=
121+
eq_singleton_iff_nonempty_unique_mem.2 ⟨(singleton_nonempty _).sym n,
122+
λ s hs, sym.eq_repeat_iff.2 $ λ b hb, eq_of_mem_singleton $ mem_sym_iff.1 hs _ hb⟩
123+
124+
lemma eq_empty_of_sym_eq_empty (h : s.sym n = ∅) : s = ∅ :=
125+
begin
126+
rw ←not_nonempty_iff_eq_empty at ⊢ h,
127+
exact λ hs, h (hs.sym _),
128+
end
129+
130+
@[simp] lemma sym_eq_empty : s.sym n = ∅ ↔ n ≠ 0 ∧ s = ∅ :=
131+
begin
132+
cases n,
133+
{ exact iff_of_false (singleton_ne_empty _) (λ h, (h.1 rfl).elim) },
134+
{ refine ⟨λ h, ⟨n.succ_ne_zero, eq_empty_of_sym_eq_empty h⟩, _⟩,
135+
rintro ⟨_, rfl⟩,
136+
exact sym_empty _ }
137+
end
138+
139+
@[simp] lemma sym_nonempty : (s.sym n).nonempty ↔ n = 0 ∨ s.nonempty :=
140+
by simp_rw [nonempty_iff_ne_empty, ne.def, sym_eq_empty, not_and_distrib, not_ne_iff]
141+
142+
alias sym2_nonempty ↔ _ finset.nonempty.sym2
143+
144+
attribute [protected] finset.nonempty.sym2
145+
146+
@[simp] lemma sym_univ [fintype α] (n : ℕ) : (univ : finset α).sym n = univ :=
147+
eq_univ_iff_forall.2 $ λ s, mem_sym_iff.2 $ λ a _, mem_univ _
148+
149+
@[simp] lemma sym_mono (h : s ⊆ t) (n : ℕ): s.sym n ⊆ t.sym n :=
150+
λ m hm, mem_sym_iff.2 $ λ a ha, h $ mem_sym_iff.1 hm _ ha
151+
152+
@[simp] lemma sym_inter (s t : finset α) (n : ℕ) : (s ∩ t).sym n = s.sym n ∩ t.sym n :=
153+
by { ext m, simp only [mem_inter, mem_sym_iff, imp_and_distrib, forall_and_distrib] }
154+
155+
@[simp] lemma sym_union (s t : finset α) (n : ℕ) : s.sym n ∪ t.sym n ⊆ (s ∪ t).sym n :=
156+
union_subset (sym_mono (subset_union_left s t) n) (sym_mono (subset_union_right s t) n)
157+
158+
end sym
159+
end finset

src/data/sym/basic.lean

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ show these are equivalent in `sym.sym_equiv_sym'`.
3838
-/
3939
def sym (α : Type u) (n : ℕ) := {s : multiset α // s.card = n}
4040

41+
instance sym.has_coe (α : Type*) (n : ℕ) : has_coe (sym α n) (multiset α) := coe_subtype
42+
4143
/--
4244
This is the `list.perm` setoid lifted to `vector`.
4345
@@ -51,7 +53,7 @@ local attribute [instance] vector.perm.is_setoid
5153

5254
namespace sym
5355

54-
variables {α : Type u} {n : ℕ}
56+
variables {α : Type u} {n : ℕ} {s : sym α n} {a b : α}
5557

5658
/--
5759
The unique element in `sym α 0`.
@@ -157,6 +159,17 @@ def repeat (a : α) (n : ℕ) : sym α n := ⟨multiset.repeat a n, multiset.car
157159

158160
lemma repeat_succ {a : α} {n : ℕ} : repeat a n.succ = a :: repeat a n := rfl
159161

162+
lemma coe_repeat : (repeat a n : multiset α) = multiset.repeat a n := rfl
163+
164+
@[simp] lemma mem_repeat : b ∈ repeat a n ↔ n ≠ 0 ∧ b = a := multiset.mem_repeat
165+
166+
lemma eq_repeat_iff : s = repeat a n ↔ ∀ b ∈ s, b = a :=
167+
begin
168+
rw [subtype.ext_iff, coe_repeat],
169+
convert multiset.eq_repeat',
170+
exact s.2.symm,
171+
end
172+
160173
lemma exists_mem (s : sym α n.succ) : ∃ a, a ∈ s :=
161174
multiset.card_pos_iff_exists_mem.1 $ s.2.symm ▸ n.succ_pos
162175

src/data/sym/card.lean

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Yaël Dillies, Bhavik Mehta
55
-/
66
import algebra.big_operators.basic
7-
import data.sym.sym2
7+
import data.finset.sym
88

99
/-!
1010
# Stars and bars
@@ -42,8 +42,7 @@ namespace sym2
4242
variables {α : Type*} [decidable_eq α]
4343

4444
/-- The `diag` of `s : finset α` is sent on a finset of `sym2 α` of card `s.card`. -/
45-
lemma card_image_diag (s : finset α) :
46-
(s.diag.image quotient.mk).card = s.card :=
45+
lemma card_image_diag (s : finset α) : (s.diag.image quotient.mk).card = s.card :=
4746
begin
4847
rw [card_image_of_inj_on, diag_card],
4948
rintro ⟨x₀, x₁⟩ hx _ _ h,
@@ -105,10 +104,21 @@ begin
105104
exact and_iff_right ⟨a, mem_univ _, ha⟩,
106105
end
107106

108-
protected lemma card [fintype α] :
109-
card (sym2 α) = card α * (card α + 1) / 2 :=
110-
by rw [←fintype.card_congr (@equiv.sum_compl _ is_diag (sym2.is_diag.decidable_pred α)),
111-
fintype.card_sum, card_subtype_diag, card_subtype_not_diag, nat.choose_two_right, add_comm,
112-
←nat.triangle_succ, nat.succ_sub_one, mul_comm]
107+
/-- Finset **stars and bars** for the case `n = 2`. -/
108+
lemma _root_.finset.card_sym2 (s : finset α) : s.sym2.card = s.card * (s.card + 1) / 2 :=
109+
begin
110+
rw [←image_diag_union_image_off_diag, card_union_eq, sym2.card_image_diag,
111+
sym2.card_image_off_diag, nat.choose_two_right, add_comm, ←nat.triangle_succ, nat.succ_sub_one,
112+
mul_comm],
113+
rintro m he,
114+
rw [inf_eq_inter, mem_inter, mem_image, mem_image] at he,
115+
obtain ⟨⟨a, ha, rfl⟩, b, hb, hab⟩ := he,
116+
refine not_is_diag_mk_of_mem_off_diag hb _,
117+
rw hab,
118+
exact is_diag_mk_of_mem_diag ha,
119+
end
120+
121+
/-- Type **stars and bars** for the case `n = 2`. -/
122+
protected lemma card [fintype α] : card (sym2 α) = card α * (card α + 1) / 2 := finset.card_sym2 _
113123

114124
end sym2

src/data/sym/sym2.lean

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,21 @@ instance : has_mem α (sym2 α) := ⟨mem⟩
176176
lemma mem_mk_left (x y : α) : x ∈ ⟦(x, y)⟧ := ⟨y, rfl⟩
177177
lemma mem_mk_right (x y : α) : y ∈ ⟦(x, y)⟧ := eq_swap.subst $ mem_mk_left y x
178178

179+
@[simp] lemma mem_iff {a b c : α} : a ∈ ⟦(b, c)⟧ ↔ a = b ∨ a = c :=
180+
{ mp := by { rintro ⟨_, h⟩, rw eq_iff at h, tidy },
181+
mpr := by { rintro ⟨_⟩; subst a, { apply mem_mk_left }, apply mem_mk_right } }
182+
183+
lemma out_fst_mem (e : sym2 α) : e.out.1 ∈ e := ⟨e.out.2, by rw [prod.mk.eta, e.out_eq]⟩
184+
lemma out_snd_mem (e : sym2 α) : e.out.2 ∈ e := ⟨e.out.1, by rw [eq_swap, prod.mk.eta, e.out_eq]⟩
185+
186+
lemma ball {p : α → Prop} {a b : α} : (∀ c ∈ ⟦(a, b)⟧, p c) ↔ p a ∧ p b :=
187+
begin
188+
refine ⟨λ h, ⟨h _ $ mem_mk_left _ _, h _ $ mem_mk_right _ _⟩, λ h c hc, _⟩,
189+
obtain rfl | rfl := sym2.mem_iff.1 hc,
190+
{ exact h.1 },
191+
{ exact h.2 }
192+
end
193+
179194
/--
180195
Given an element of the unordered pair, give the other element using `classical.some`.
181196
See also `mem.other'` for the computable version.
@@ -187,10 +202,6 @@ classical.some h
187202
lemma other_spec {a : α} {z : sym2 α} (h : a ∈ z) : ⟦(a, h.other)⟧ = z :=
188203
by erw ← classical.some_spec h
189204

190-
@[simp] lemma mem_iff {a b c : α} : a ∈ ⟦(b, c)⟧ ↔ a = b ∨ a = c :=
191-
{ mp := by { rintro ⟨_, h⟩, rw eq_iff at h, tidy },
192-
mpr := by { rintro ⟨_⟩; subst a, { apply mem_mk_left }, apply mem_mk_right } }
193-
194205
lemma other_mem {a : α} {z : sym2 α} (h : a ∈ z) : h.other ∈ z :=
195206
by { convert mem_mk_right a h.other, rw other_spec h }
196207

0 commit comments

Comments
 (0)