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

Commit 13b9478

Browse files
b-mehtaagusakov
andcommitted
feat(combinatorics/colex): introduce colexicographical order (#4858)
We define the colex ordering for finite sets, and give a couple of important lemmas and properties relating to it. Part of #2770, in order to prove the Kruskal-Katona theorem. Co-authored-by: Alena Gusakov <agusakov@udel.edu>
1 parent 83ec6e0 commit 13b9478

File tree

1 file changed

+346
-0
lines changed

1 file changed

+346
-0
lines changed

src/combinatorics/colex.lean

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/-
2+
Copyright (c) 2020 Bhavik Mehta. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Bhavik Mehta, Alena Gusakov
5+
-/
6+
import data.finset
7+
import data.fintype.basic
8+
import algebra.geom_sum
9+
import tactic
10+
11+
/-!
12+
# Colex
13+
14+
We define the colex ordering for finite sets, and give a couple of important
15+
lemmas and properties relating to it.
16+
17+
The colex ordering likes to avoid large values - it can be thought of on
18+
`finset ℕ` as the "binary" ordering. That is, order A based on
19+
`∑_{i ∈ A} 2^i`.
20+
It's defined here in a slightly more general way, requiring only `has_lt α` in
21+
the definition of colex on `finset α`. In the context of the Kruskal-Katona
22+
theorem, we are interested in particular on how colex behaves for sets of a
23+
fixed size. If the size is 3, colex on ℕ starts
24+
123, 124, 134, 234, 125, 135, 235, 145, 245, 345, ...
25+
26+
## Main statements
27+
* `colex_hom`: strictly monotone functions preserve colex
28+
* Colex order properties - linearity, decidability and so on.
29+
* `forall_lt_of_colex_lt_of_forall_lt`: if A < B in colex, and everything
30+
in B is < t, then everything in A is < t. This confirms the idea that
31+
an enumeration under colex will exhaust all sets using elements < t before
32+
allowing t to be included.
33+
* `binary_iff`: colex for α = ℕ is the same as binary
34+
(this also proves binary expansions are unique)
35+
36+
## Notation
37+
We define `<` and `≤` to denote colex ordering, useful in particular when
38+
multiple orderings are available in context.
39+
40+
## Tags
41+
colex, colexicographic, binary
42+
43+
## References
44+
* https://github.com/b-mehta/maths-notes/blob/master/iii/mich/combinatorics.pdf
45+
46+
## Todo
47+
Show the subset ordering is a sub-relation of the colex ordering.
48+
-/
49+
50+
variable {α : Type*}
51+
52+
open finset
53+
54+
/--
55+
We define this type synonym to refer to the colexicographic ordering on finsets
56+
rather than the natural subset ordering.
57+
-/
58+
@[derive inhabited]
59+
def finset.colex (α) := finset α
60+
61+
/--
62+
A convenience constructor to turn a `finset α` into a `finset.colex α`, useful in order to
63+
use the colex ordering rather than the subset ordering.
64+
-/
65+
def finset.to_colex {α} (s : finset α) : finset.colex α := s
66+
67+
@[simp]
68+
lemma colex.eq_iff (A B : finset α) :
69+
A.to_colex = B.to_colex ↔ A = B := by refl
70+
71+
/--
72+
`A` is less than `B` in the colex ordering if the largest thing that's not in both sets is in B.
73+
In other words, max (A ▵ B) ∈ B (if the maximum exists).
74+
-/
75+
instance [has_lt α] : has_lt (finset.colex α) :=
76+
⟨λ (A B : finset α), ∃ (k : α), (∀ {x}, k < x → (x ∈ A ↔ x ∈ B)) ∧ k ∉ A ∧ k ∈ B⟩
77+
78+
/-- We can define (≤) in the obvious way. -/
79+
instance [has_lt α] : has_le (finset.colex α) :=
80+
⟨λ A B, A < B ∨ A = B⟩
81+
82+
lemma colex.lt_def [has_lt α] (A B : finset α) :
83+
A.to_colex < B.to_colex ↔ ∃ k, (∀ {x}, k < x → (x ∈ A ↔ x ∈ B)) ∧ k ∉ A ∧ k ∈ B :=
84+
iff.rfl
85+
lemma colex.le_def [has_lt α] (A B : finset α) :
86+
A.to_colex ≤ B.to_colex ↔ A.to_colex < B.to_colex ∨ A = B :=
87+
iff.rfl
88+
89+
/-- If everything in A is less than k, we can bound the sum of powers. -/
90+
lemma nat.sum_pow_two_lt {k : ℕ} {A : finset ℕ} (h₁ : ∀ {x}, x ∈ A → x < k) :
91+
A.sum (pow 2) < 2^k :=
92+
begin
93+
apply lt_of_le_of_lt (sum_le_sum_of_subset (λ t, mem_range.2 ∘ h₁)),
94+
have z := geom_sum_mul_add 1 k,
95+
rw [geom_series, mul_one, one_add_one_eq_two] at z,
96+
rw ← z,
97+
apply nat.lt_succ_self,
98+
end
99+
100+
namespace colex
101+
102+
/-- Strictly monotone functions preserve the colex ordering. -/
103+
lemma hom {β : Type*} [linear_order α] [decidable_eq β] [preorder β]
104+
{f : α → β} (h₁ : strict_mono f) (A B : finset α) :
105+
(A.image f).to_colex < (B.image f).to_colex ↔ A.to_colex < B.to_colex :=
106+
begin
107+
simp only [colex.lt_def, not_exists, mem_image, exists_prop, not_and],
108+
split,
109+
{ rintro ⟨k, z, q, k', _, rfl⟩,
110+
exact ⟨k', λ x hx, by simpa [h₁.injective] using z (h₁ hx), λ t, q _ t rfl, ‹k' ∈ B›⟩ },
111+
rintro ⟨k, z, ka, _⟩,
112+
refine ⟨f k, λ x hx, _, _, k, ‹k ∈ B›, rfl⟩,
113+
{ split,
114+
any_goals {
115+
rintro ⟨x', hx', rfl⟩,
116+
refine ⟨x', _, rfl⟩,
117+
rwa ← z _ <|> rwa z _,
118+
rwa strict_mono.lt_iff_lt h₁ at hx } },
119+
{ simp only [h₁.injective, function.injective.eq_iff],
120+
exact λ x hx, ne_of_mem_of_not_mem hx ka }
121+
end
122+
123+
/-- A special case of `colex_hom` which is sometimes useful. -/
124+
@[simp] lemma hom_fin {n : ℕ} (A B : finset (fin n)) :
125+
finset.to_colex (A.image (λ n, (n : ℕ))) < finset.to_colex (B.image (λ n, (n : ℕ)))
126+
↔ finset.to_colex A < finset.to_colex B :=
127+
colex.hom (λ x y k, k) _ _
128+
129+
instance [has_lt α] : is_irrefl (finset.colex α) (<) :=
130+
⟨λ A h, exists.elim h (λ _ ⟨_,a,b⟩, a b)⟩
131+
132+
@[trans]
133+
lemma lt_trans [linear_order α] {a b c : finset.colex α} :
134+
a < b → b < c → a < c :=
135+
begin
136+
rintros ⟨k₁, k₁z, notinA, inB⟩ ⟨k₂, k₂z, notinB, inC⟩,
137+
cases lt_or_gt_of_ne (ne_of_mem_of_not_mem inB notinB),
138+
{ refine ⟨k₂, _, by rwa k₁z h, inC⟩,
139+
intros x hx,
140+
rw ← k₂z hx,
141+
apply k₁z (trans h hx) },
142+
{ refine ⟨k₁, _, notinA, by rwa ← k₂z h⟩,
143+
intros x hx,
144+
rw k₁z hx,
145+
apply k₂z (trans h hx) }
146+
end
147+
148+
@[trans]
149+
lemma le_trans [linear_order α] (a b c : finset.colex α) :
150+
a ≤ b → b ≤ c → a ≤ c :=
151+
λ AB BC, AB.elim (λ k, BC.elim (λ t, or.inl (lt_trans k t)) (λ t, t ▸ AB)) (λ k, k.symm ▸ BC)
152+
153+
instance [linear_order α] : is_trans (finset.colex α) (<) := ⟨λ _ _ _, colex.lt_trans⟩
154+
155+
instance [linear_order α] : is_asymm (finset.colex α) (<) := by apply_instance
156+
157+
instance [linear_order α] : is_strict_order (finset.colex α) (<) := {}
158+
159+
lemma lt_trichotomy [linear_order α] (A B : finset.colex α) :
160+
A < B ∨ A = B ∨ B < A :=
161+
begin
162+
by_cases h₁ : (A = B),
163+
{ tauto },
164+
rcases (exists_max_image (A \ B ∪ B \ A) id _) with ⟨k, hk, z⟩,
165+
{ simp only [mem_union, mem_sdiff] at hk,
166+
cases hk,
167+
{ right,
168+
right,
169+
refine ⟨k, λ t th, _, hk.2, hk.1⟩,
170+
specialize z t,
171+
by_contra h₂,
172+
simp only [mem_union, mem_sdiff, id.def] at z,
173+
rw [not_iff, iff_iff_and_or_not_and_not, not_not, and_comm] at h₂,
174+
apply not_le_of_lt th (z h₂) },
175+
{ left,
176+
refine ⟨k, λ t th, _, hk.2, hk.1⟩,
177+
specialize z t,
178+
by_contra h₃,
179+
simp only [mem_union, mem_sdiff, id.def] at z,
180+
rw [not_iff, iff_iff_and_or_not_and_not, not_not, and_comm, or_comm] at h₃,
181+
apply not_le_of_lt th (z h₃) }, },
182+
rw nonempty_iff_ne_empty,
183+
intro a,
184+
simp only [union_eq_empty_iff, sdiff_eq_empty_iff_subset] at a,
185+
apply h₁ (subset.antisymm a.1 a.2)
186+
end
187+
188+
instance [linear_order α] : is_trichotomous (finset.colex α) (<) := ⟨lt_trichotomy⟩
189+
190+
-- It should be possible to do this computably but it doesn't seem to make any difference for now.
191+
noncomputable instance [linear_order α] : linear_order (finset.colex α) :=
192+
{ le_refl := λ A, or.inr rfl,
193+
le_trans := le_trans,
194+
le_antisymm := λ A B AB BA, AB.elim (λ k, BA.elim (λ t, (asymm k t).elim) (λ t, t.symm)) id,
195+
le_total := λ A B,
196+
(lt_trichotomy A B).elim3 (or.inl ∘ or.inl) (or.inl ∘ or.inr) (or.inr ∘ or.inl),
197+
decidable_le := classical.dec_rel _,
198+
..finset.colex.has_le }
199+
200+
instance [linear_order α] : is_incomp_trans (finset.colex α) (<) :=
201+
begin
202+
constructor,
203+
rintros A B C ⟨nAB, nBA⟩ ⟨nBC, nCB⟩,
204+
have : A = B := ((lt_trichotomy A B).resolve_left nAB).resolve_right nBA,
205+
have : B = C := ((lt_trichotomy B C).resolve_left nBC).resolve_right nCB,
206+
rw [‹A = B›, ‹B = C›, and_self],
207+
apply irrefl
208+
end
209+
210+
instance [linear_order α] : is_strict_weak_order (finset.colex α) (<) := {}
211+
212+
instance [linear_order α] : is_strict_total_order (finset.colex α) (<) := {}
213+
214+
/-- If {r} is less than or equal to s in the colexicographical sense,
215+
then s contains an element greater than or equal to r. -/
216+
lemma mem_le_of_singleton_le [linear_order α] {r : α} {s : finset α}:
217+
({r} : finset α).to_colex ≤ s.to_colex → ∃ x ∈ s, r ≤ x :=
218+
begin
219+
intro h,
220+
rw colex.le_def at h,
221+
cases h with lt eq,
222+
{ rw colex.lt_def at lt,
223+
rcases lt with ⟨k, hk, hi, hj⟩,
224+
by_cases hr : r ∈ s,
225+
{ use r,
226+
tauto },
227+
{ contrapose! hk,
228+
simp only [mem_singleton],
229+
specialize hk k,
230+
use r,
231+
split,
232+
{ apply hk,
233+
cc },
234+
{ simp,
235+
exact hr } } },
236+
{ rw ← eq,
237+
use r,
238+
simp only [true_and, eq_self_iff_true, mem_singleton] },
239+
end
240+
241+
/-- s.to_colex < finset.to_colex {r} iff all elements of s are less than r. -/
242+
lemma lt_singleton_iff_mem_lt [linear_order α] {r : α} {s : finset α}:
243+
s.to_colex < finset.to_colex {r} ↔ ∀ x ∈ s, x < r :=
244+
begin
245+
simp only [lt_def, mem_singleton, ← and_assoc, exists_eq_right],
246+
split,
247+
{ rintro ⟨q, rs⟩ x hx,
248+
by_contra h,
249+
rw not_lt at h,
250+
cases lt_or_eq_of_le h with h₁ h₁,
251+
{ rw q h₁ at hx,
252+
subst hx,
253+
apply lt_irrefl x h₁ },
254+
{ apply rs,
255+
rwa h₁ } },
256+
{ intro h,
257+
refine ⟨λ z hz, _, _⟩,
258+
{ split,
259+
{ intro hr,
260+
exfalso,
261+
apply lt_asymm (h _ hr) hz },
262+
{ rintro rfl,
263+
apply (lt_irrefl _ hz).elim } },
264+
{ intro rs,
265+
apply lt_irrefl _ (h _ rs) } }
266+
end
267+
268+
/-- Colex is an extension of the base ordering on α. -/
269+
lemma singleton_lt_iff_lt [linear_order α] {r s : α} :
270+
({r} : finset α).to_colex < ({s} : finset α).to_colex ↔ r < s :=
271+
begin
272+
rw colex.lt_def,
273+
simp only [mem_singleton, ← and_assoc, exists_eq_right],
274+
split,
275+
{ rintro ⟨q, p⟩,
276+
apply lt_of_le_of_ne _ (ne.symm p),
277+
contrapose! p,
278+
rw (q p).1 rfl },
279+
{ intro a,
280+
exact ⟨λ z hz, iff_of_false (ne_of_gt (trans hz a)) (ne_of_gt hz), ne_of_gt a⟩ }
281+
end
282+
283+
/--
284+
If A is before B in colex, and everything in B is small, then everything in A is small.
285+
-/
286+
lemma forall_lt_of_colex_lt_of_forall_lt [linear_order α] {A B : finset α}
287+
(t : α) (h₁ : A.to_colex < B.to_colex) (h₂ : ∀ x ∈ B, x < t) :
288+
∀ x ∈ A, x < t :=
289+
begin
290+
rw colex.lt_def at h₁,
291+
rcases h₁ with ⟨k, z, _, _⟩,
292+
intros x hx,
293+
apply lt_of_not_ge,
294+
intro a,
295+
refine not_lt_of_ge a (h₂ x _),
296+
rwa ← z,
297+
apply lt_of_lt_of_le (h₂ k ‹_›) a,
298+
end
299+
300+
/-- Colex doesn't care if you remove the other set -/
301+
@[simp] lemma sdiff_lt_sdiff_iff_lt [has_lt α] [decidable_eq α] (A B : finset α) :
302+
(A \ B).to_colex < (B \ A).to_colex ↔ A.to_colex < B.to_colex :=
303+
begin
304+
rw [colex.lt_def, colex.lt_def],
305+
apply exists_congr,
306+
intro k,
307+
simp only [mem_sdiff, not_and, not_not],
308+
split,
309+
{ rintro ⟨z, kAB, kB, kA⟩,
310+
refine ⟨_, kA, kB⟩,
311+
{ intros x hx,
312+
specialize z hx,
313+
tauto } },
314+
{ rintro ⟨z, kA, kB⟩,
315+
refine ⟨_, λ _, kB, kB, kA⟩,
316+
intros x hx,
317+
rw z hx },
318+
end
319+
320+
/-- For subsets of ℕ, we can show that colex is equivalent to binary. -/
321+
lemma sum_pow_two_lt_iff_lt (A B : finset ℕ) : A.sum (pow 2) < B.sum (pow 2) ↔
322+
A.to_colex < B.to_colex :=
323+
begin
324+
have z : ∀ (A B : finset ℕ), A.to_colex < B.to_colex → A.sum (pow 2) < B.sum (pow 2),
325+
{ intros A B,
326+
rw [← sdiff_lt_sdiff_iff_lt, colex.lt_def],
327+
rintro ⟨k, z, kA, kB⟩,
328+
rw ← sdiff_union_inter A B,
329+
conv_rhs { rw ← sdiff_union_inter B A },
330+
rw [sum_union (disjoint_sdiff_inter _ _), sum_union (disjoint_sdiff_inter _ _),
331+
inter_comm, add_lt_add_iff_right],
332+
apply lt_of_lt_of_le (@nat.sum_pow_two_lt k (A \ B) _),
333+
{ apply single_le_sum (λ _ _, nat.zero_le _) kB },
334+
intros x hx,
335+
apply lt_of_le_of_ne (le_of_not_lt (λ kx, _)),
336+
{ apply (ne_of_mem_of_not_mem hx kA) },
337+
specialize z kx,
338+
have := z.1 hx,
339+
rw mem_sdiff at this hx,
340+
exact hx.2 this.1 },
341+
refine ⟨λ h, (lt_trichotomy A B).resolve_right (λ h₁, h₁.elim _ (not_lt_of_gt h ∘ z _ _)), z A B⟩,
342+
rintro rfl,
343+
apply irrefl _ h
344+
end
345+
346+
end colex

0 commit comments

Comments
 (0)