-
Notifications
You must be signed in to change notification settings - Fork 298
/
young_diagram.lean
308 lines (221 loc) · 12 KB
/
young_diagram.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/-
Copyright (c) 2022 Jake Levinson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jake Levinson
-/
import order.upper_lower
import data.finset.preimage
/-!
# Young diagrams
A Young diagram is a finite set of up-left justified boxes:
```text
□□□□□
□□□
□□□
□
```
This Young diagram corresponds to the [5, 3, 3, 1] partition of 12.
We represent it as a lower set in `ℕ × ℕ` in the product partial order. We write `(i, j) ∈ μ`
to say that `(i, j)` (in matrix coordinates) is in the Young diagram `μ`.
## Main definitions
- `young_diagram` : Young diagrams
- `young_diagram.card` : the number of cells in a Young diagram (its *cardinality*)
- `young_diagram.distrib_lattice` : a distributive lattice instance for Young diagrams
ordered by containment, with `(⊥ : young_diagram)` the empty diagram.
- `young_diagram.row` and `young_diagram.row_len`: rows of a Young diagram and their lengths
- `young_diagram.col` and `young_diagram.col_len`: columns of a Young diagram and their lengths
## Notation
In "English notation", a Young diagram is drawn so that (i1, j1) ≤ (i2, j2)
means (i1, j1) is weakly up-and-left of (i2, j2). This terminology is used
below, e.g. in `young_diagram.up_left_mem`.
## Tags
Young diagram
## References
<https://en.wikipedia.org/wiki/Young_tableau>
-/
/-- A Young diagram is a finite collection of cells on the `ℕ × ℕ` grid such that whenever
a cell is present, so are all the ones above and to the left of it. Like matrices, an `(i, j)` cell
is a cell in row `i` and column `j`, where rows are enumerated downward and columns rightward.
Young diagrams are modeled as finite sets in `ℕ × ℕ` that are lower sets with respect to the
standard order on products. -/
@[ext] structure young_diagram :=
(cells : finset (ℕ × ℕ))
(is_lower_set : is_lower_set (cells : set (ℕ × ℕ)))
namespace young_diagram
instance : set_like young_diagram (ℕ × ℕ) :=
{ coe := coe young_diagram.cells,
coe_injective' := λ μ ν h, by { rwa [young_diagram.ext_iff, ← finset.coe_inj] } }
@[simp] lemma mem_cells {μ : young_diagram} (c : ℕ × ℕ) :
c ∈ μ.cells ↔ c ∈ μ := iff.rfl
@[simp] lemma mem_mk (c : ℕ × ℕ) (cells) (is_lower_set) :
c ∈ young_diagram.mk cells is_lower_set ↔ c ∈ cells := iff.rfl
instance decidable_mem (μ : young_diagram) : decidable_pred (∈ μ) :=
show decidable_pred (∈ μ.cells), by apply_instance
/-- In "English notation", a Young diagram is drawn so that (i1, j1) ≤ (i2, j2)
means (i1, j1) is weakly up-and-left of (i2, j2). -/
lemma up_left_mem (μ : young_diagram) {i1 i2 j1 j2 : ℕ}
(hi : i1 ≤ i2) (hj : j1 ≤ j2) (hcell : (i2, j2) ∈ μ) : (i1, j1) ∈ μ :=
μ.is_lower_set (prod.mk_le_mk.mpr ⟨hi, hj⟩) hcell
section distrib_lattice
@[simp] lemma cells_subset_iff {μ ν : young_diagram} : μ.cells ⊆ ν.cells ↔ μ ≤ ν := iff.rfl
@[simp] lemma cells_ssubset_iff {μ ν : young_diagram} : μ.cells ⊂ ν.cells ↔ μ < ν := iff.rfl
instance : has_sup young_diagram :=
{ sup := λ μ ν, { cells := μ.cells ∪ ν.cells,
is_lower_set := by { rw finset.coe_union,
exact μ.is_lower_set.union ν.is_lower_set } } }
@[simp] lemma cells_sup (μ ν : young_diagram) : (μ ⊔ ν).cells = μ.cells ∪ ν.cells := rfl
@[simp, norm_cast] lemma coe_sup (μ ν : young_diagram) : ↑(μ ⊔ ν) = (μ ∪ ν : set (ℕ × ℕ)) :=
finset.coe_union _ _
@[simp] lemma mem_sup {μ ν : young_diagram} {x : ℕ × ℕ} : x ∈ (μ ⊔ ν) ↔ x ∈ μ ∨ x ∈ ν :=
finset.mem_union
instance : has_inf young_diagram :=
{ inf := λ μ ν, { cells := μ.cells ∩ ν.cells,
is_lower_set := by { rw finset.coe_inter,
exact μ.is_lower_set.inter ν.is_lower_set } } }
@[simp] lemma cells_inf (μ ν : young_diagram) : (μ ⊓ ν).cells = μ.cells ∩ ν.cells := rfl
@[simp, norm_cast] lemma coe_inf (μ ν : young_diagram) : ↑(μ ⊓ ν) = (μ ∩ ν : set (ℕ × ℕ)) :=
finset.coe_inter _ _
@[simp] lemma mem_inf {μ ν : young_diagram} {x : ℕ × ℕ} : x ∈ (μ ⊓ ν) ↔ x ∈ μ ∧ x ∈ ν :=
finset.mem_inter
/-- The empty Young diagram is (⊥ : young_diagram). -/
instance : order_bot young_diagram :=
{ bot := { cells := ∅, is_lower_set := λ _ _ _, false.elim }, bot_le := λ _ _, false.elim }
@[simp] lemma cells_bot : (⊥ : young_diagram).cells = ∅ := rfl
@[simp, norm_cast] lemma coe_bot : ↑(⊥ : young_diagram) = (∅ : set (ℕ × ℕ)) := rfl
@[simp] lemma not_mem_bot (x : ℕ × ℕ) : x ∉ (⊥ : young_diagram) := finset.not_mem_empty x
instance : inhabited young_diagram := ⟨⊥⟩
instance : distrib_lattice young_diagram :=
function.injective.distrib_lattice
young_diagram.cells
(λ μ ν h, by rwa young_diagram.ext_iff)
(λ _ _, rfl) (λ _ _, rfl)
end distrib_lattice
/-- Cardinality of a Young diagram -/
@[reducible] protected def card (μ : young_diagram) : ℕ := μ.cells.card
section transpose
/-- The `transpose` of a Young diagram is obtained by swapping i's with j's. -/
def transpose (μ : young_diagram) : young_diagram :=
{ cells := (equiv.prod_comm _ _).finset_congr μ.cells,
is_lower_set := λ _ _ h, begin
simp only [finset.mem_coe, equiv.finset_congr_apply, finset.mem_map_equiv],
intro hcell,
apply μ.is_lower_set _ hcell,
simp [h],
end }
@[simp] lemma mem_transpose {μ : young_diagram} {c : ℕ × ℕ} : c ∈ μ.transpose ↔ c.swap ∈ μ :=
by simp [transpose]
@[simp] lemma transpose_transpose (μ : young_diagram) : μ.transpose.transpose = μ :=
by { ext, simp }
lemma transpose_eq_iff_eq_transpose {μ ν : young_diagram} :
μ.transpose = ν ↔ μ = ν.transpose :=
by { split; { rintro rfl, simp } }
@[simp] lemma transpose_eq_iff {μ ν : young_diagram} :
μ.transpose = ν.transpose ↔ μ = ν :=
by { rw transpose_eq_iff_eq_transpose, simp }
-- This is effectively both directions of `transpose_le_iff` below.
protected lemma le_of_transpose_le {μ ν : young_diagram} (h_le : μ.transpose ≤ ν) :
μ ≤ ν.transpose :=
λ c hc, by { simp only [mem_transpose], apply h_le, simpa }
@[simp] lemma transpose_le_iff {μ ν : young_diagram} : μ.transpose ≤ ν.transpose ↔ μ ≤ ν :=
⟨ λ h, by { convert young_diagram.le_of_transpose_le h, simp },
λ h, by { convert @young_diagram.le_of_transpose_le _ _ _, simpa } ⟩
@[mono]
protected lemma transpose_mono {μ ν : young_diagram} (h_le : μ ≤ ν) : μ.transpose ≤ ν.transpose :=
transpose_le_iff.mpr h_le
/-- Transposing Young diagrams is an `order_iso`. -/
@[simps] def transpose_order_iso : young_diagram ≃o young_diagram :=
⟨⟨transpose, transpose, λ _, by simp, λ _, by simp⟩, by simp⟩
end transpose
section rows
/-! ### Rows and row lengths of Young diagrams.
This section defines `μ.row` and `μ.row_len`, with the following API:
1. `(i, j) ∈ μ ↔ j < μ.row_len i`
2. `μ.row i = {i} ×ˢ (finset.range (μ.row_len i))`
3. `μ.row_len i = (μ.row i).card`
4. `∀ {i1 i2}, i1 ≤ i2 → μ.row_len i2 ≤ μ.row_len i1`
Note: #3 is not convenient for defining `μ.row_len`; instead, `μ.row_len` is defined
as the smallest `j` such that `(i, j) ∉ μ`. -/
/-- The `i`-th row of a Young diagram consists of the cells whose first coordinate is `i`. -/
def row (μ : young_diagram) (i : ℕ) : finset (ℕ × ℕ) := μ.cells.filter (λ c, c.fst = i)
lemma mem_row_iff {μ : young_diagram} {i : ℕ} {c : ℕ × ℕ} : c ∈ μ.row i ↔ c ∈ μ ∧ c.fst = i :=
by simp [row]
lemma mk_mem_row_iff {μ : young_diagram} {i j : ℕ} : (i, j) ∈ μ.row i ↔ (i, j) ∈ μ :=
by simp [row]
protected lemma exists_not_mem_row (μ : young_diagram) (i : ℕ) : ∃ j, (i, j) ∉ μ :=
begin
obtain ⟨j, hj⟩ := infinite.exists_not_mem_finset
((μ.cells).preimage (prod.mk i) (λ _ _ _ _ h, by {cases h, refl})),
rw finset.mem_preimage at hj,
exact ⟨j, hj⟩,
end
/-- Length of a row of a Young diagram -/
def row_len (μ : young_diagram) (i : ℕ) : ℕ := nat.find $ μ.exists_not_mem_row i
lemma mem_iff_lt_row_len {μ : young_diagram} {i j : ℕ} : (i, j) ∈ μ ↔ j < μ.row_len i :=
by { rw [row_len, nat.lt_find_iff], push_neg,
exact ⟨λ h _ hmj, μ.up_left_mem (by refl) hmj h, λ h, h _ (by refl)⟩ }
lemma row_eq_prod {μ : young_diagram} {i : ℕ} : μ.row i = {i} ×ˢ finset.range (μ.row_len i) :=
by { ext ⟨a, b⟩,
simp only [finset.mem_product, finset.mem_singleton, finset.mem_range,
mem_row_iff, mem_iff_lt_row_len, and_comm, and.congr_right_iff],
rintro rfl, refl }
lemma row_len_eq_card (μ : young_diagram) {i : ℕ} : μ.row_len i = (μ.row i).card :=
by simp [row_eq_prod]
@[mono]
lemma row_len_anti (μ : young_diagram) (i1 i2 : ℕ) (hi : i1 ≤ i2) : μ.row_len i2 ≤ μ.row_len i1 :=
by { by_contra' h_lt, rw ← lt_self_iff_false (μ.row_len i1),
rw ← mem_iff_lt_row_len at h_lt ⊢,
exact μ.up_left_mem hi (by refl) h_lt }
end rows
section columns
/-! ### Columns and column lengths of Young diagrams.
This section has an identical API to the rows section. -/
/-- The `j`-th column of a Young diagram consists of the cells whose second coordinate is `j`. -/
def col (μ : young_diagram) (j : ℕ) : finset (ℕ × ℕ) := μ.cells.filter (λ c, c.snd = j)
lemma mem_col_iff {μ : young_diagram} {j : ℕ} {c : ℕ × ℕ} : c ∈ μ.col j ↔ c ∈ μ ∧ c.snd = j :=
by simp [col]
lemma mk_mem_col_iff {μ : young_diagram} {i j : ℕ} : (i, j) ∈ μ.col j ↔ (i, j) ∈ μ :=
by simp [col]
protected lemma exists_not_mem_col (μ : young_diagram) (j : ℕ) : ∃ i, (i, j) ∉ μ.cells :=
by { convert μ.transpose.exists_not_mem_row j, simp }
/-- Length of a column of a Young diagram -/
def col_len (μ : young_diagram) (j : ℕ) : ℕ := nat.find $ μ.exists_not_mem_col j
@[simp] lemma col_len_transpose (μ : young_diagram) (j : ℕ) : μ.transpose.col_len j = μ.row_len j :=
by simp [row_len, col_len]
@[simp] lemma row_len_transpose (μ : young_diagram) (i : ℕ) : μ.transpose.row_len i = μ.col_len i :=
by simp [row_len, col_len]
lemma mem_iff_lt_col_len {μ : young_diagram} {i j : ℕ} : (i, j) ∈ μ ↔ i < μ.col_len j :=
by { rw [← row_len_transpose, ← mem_iff_lt_row_len], simp }
lemma col_eq_prod {μ : young_diagram} {j : ℕ} : μ.col j = (finset.range (μ.col_len j)) ×ˢ {j} :=
by { ext ⟨a, b⟩,
simp only [finset.mem_product, finset.mem_singleton, finset.mem_range,
mem_col_iff, mem_iff_lt_col_len, and_comm, and.congr_right_iff],
rintro rfl, refl }
lemma col_len_eq_card (μ : young_diagram) {j : ℕ} : μ.col_len j = (μ.col j).card :=
by simp [col_eq_prod]
@[mono]
lemma col_len_anti (μ : young_diagram) (j1 j2 : ℕ) (hj : j1 ≤ j2) : μ.col_len j2 ≤ μ.col_len j1 :=
by { convert μ.transpose.row_len_anti j1 j2 hj; simp }
end columns
section row_lens
/-! ### The list of row lengths of a Young diagram
This section defines `μ.row_lens : list ℕ`, the list of row lengths of a Young diagram `μ`.
1. `young_diagram.row_lens_sorted` : It is weakly decreasing (`list.sorted (≥)`).
2. `young_diagram.row_lens_pos` : It is strictly positive.
-/
/-- List of row lengths of a Young diagram -/
def row_lens (μ : young_diagram) : list ℕ := (list.range $ μ.col_len 0).map μ.row_len
@[simp] lemma nth_le_row_lens {μ : young_diagram} {i : ℕ} {hi : i < μ.row_lens.length} :
μ.row_lens.nth_le i hi = μ.row_len i :=
by simp only [row_lens, list.nth_le_range, list.nth_le_map']
@[simp] lemma length_row_lens {μ : young_diagram} : μ.row_lens.length = μ.col_len 0 :=
by simp only [row_lens, list.length_map, list.length_range]
lemma row_lens_sorted (μ : young_diagram) : μ.row_lens.sorted (≥) :=
(list.pairwise_le_range _).map _ μ.row_len_anti
lemma pos_of_mem_row_lens (μ : young_diagram) (x : ℕ) (hx : x ∈ μ.row_lens) : 0 < x :=
begin
rw [row_lens, list.mem_map] at hx,
obtain ⟨i, hi, rfl : μ.row_len i = x⟩ := hx,
rwa [list.mem_range, ← mem_iff_lt_col_len, mem_iff_lt_row_len] at hi
end
end row_lens
end young_diagram