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

Commit ad5afc2

Browse files
dwarnYaelDillies
andcommitted
feat(combinatorics/hales_jewett): Hales-Jewett and Van der Waerden (#8019)
Proves the Hales-Jewett theorem (a fundamental result in Ramsey theory on combinatorial lines) and deduces (a generalised version of) Van der Waerden's theorem on arithmetic progressions. Co-authored-by: YaelDillies <yael.dillies@gmail.com>
1 parent 398027d commit ad5afc2

File tree

3 files changed

+316
-1
lines changed

3 files changed

+316
-1
lines changed

src/combinatorics/hales_jewett.lean

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/-
2+
Copyright (c) 2021 David Wärn. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: David Wärn
5+
-/
6+
import data.fintype.basic
7+
import algebra.big_operators.basic
8+
import data.equiv.fin
9+
10+
/-!
11+
# The Hales-Jewett theorem
12+
13+
We prove the Hales-Jewett theorem and deduce Van der Waerden's theorem as a corollary.
14+
15+
The Hales-Jewett theorem is a result in Ramsey theory dealing with *combinatorial lines*. Given
16+
an 'alphabet' `α : Type*` and `a b : α`, an example of a combinatorial line in `α^5` is
17+
`{ (a, x, x, b, x) | x : α }`. See `combinatorics.line` for a precise general definition. The
18+
Hales-Jewett theorem states that for any fixed finite types `α` and `κ`, there exists a (potentially
19+
huge) finite type `ι` such that whenever `ι → α` is `κ`-colored (i.e. for any coloring
20+
`C : (ι → α) → κ`), there exists a monochromatic line. We prove the Hales-Jewett theorem using
21+
the idea of *color focusing* and a *product argument*. See the proof of
22+
`combinatorics.line.exists_mono_in_high_dimension'` for details.
23+
24+
The version of Van der Waerden's theorem in this file states that whenever a commutative monoid `M`
25+
is finitely colored and `S` is a finite subset, there exists a monochromatic homothetic copy of `S`.
26+
This follows from the Hales-Jewett theorem by considering the map `(ι → S) → M` sending `v`
27+
to `∑ i : ι, v i`, which sends a combinatorial line to a homothetic copy of `S`.
28+
29+
## Main results
30+
31+
- `combinatorics.line.exists_mono_in_high_dimension`: the Hales-Jewett theorem.
32+
- `combinatorics.exists_mono_homothetic_copy`: a generalization of Van der Waerden's theorem.
33+
34+
## Implementation details
35+
36+
For convenience, we work directly with finite types instead of natural numbers. That is, we write
37+
`α, ι, κ` for (finite) types where one might traditionally use natural numbers `n, H, c`. This
38+
allows us to work directly with `α`, `option α`, `(ι → α) → κ`, and `ι ⊕ ι'` instead of `fin n`,
39+
`fin (n+1)`, `fin (c^(n^H))`, and `fin (H + H')`.
40+
41+
## Todo
42+
43+
- Prove a finitary version of Van der Waerden's theorem (either by compactness or by modifying the
44+
current proof).
45+
46+
- One could reformulate the proof of Hales-Jewett to give explicit upper bounds on the number of
47+
coordinates needed.
48+
49+
## Tags
50+
51+
combinatorial line, Ramsey theory, arithmetic progession
52+
53+
### References
54+
55+
* https://en.wikipedia.org/wiki/Hales%E2%80%93Jewett_theorem
56+
57+
-/
58+
59+
open_locale classical
60+
open_locale big_operators
61+
62+
universes u v
63+
64+
namespace combinatorics
65+
66+
/-- The type of combinatorial lines. A line `l : line α ι` in the hypercube `ι → α` defines a
67+
function `α → ι → α` from `α` to the hypercube, such that for each coordinate `i : ι`, the function
68+
`λ x, l x i` is either `id` or constant. We require lines to be nontrivial in the sense that
69+
`λ x, l x i` is `id` for at least one `i`.
70+
71+
Formally, a line is represented by the function `l.idx_fun : ι → option α` which says whether
72+
`λ x, l x i` is `id` (corresponding to `l.idx_fun i = none`) or constantly `y` (corresponding to
73+
`l.idx_fun i = some y`).
74+
75+
When `α` has size `1` there can be many elements of `line α ι` defining the same function. -/
76+
structure line (α ι : Type*) :=
77+
(idx_fun : ι → option α)
78+
(proper : ∃ i, idx_fun i = none)
79+
80+
namespace line
81+
82+
/- This lets us treat a line `l : line α ι` as a function `α → ι → α`. -/
83+
instance (α ι) : has_coe_to_fun (line α ι) :=
84+
⟨λ _, α → ι → α, λ l x i, (l.idx_fun i).get_or_else x⟩
85+
86+
/-- A line is monochromatic if all its points are the same color. -/
87+
def is_mono {α ι κ} (C : (ι → α) → κ) (l : line α ι) : Prop :=
88+
∃ c, ∀ x, C (l x) = c
89+
90+
/-- The diagonal line. It is the identity at every coordinate. -/
91+
def diagonal (α ι) [nonempty ι] : line α ι :=
92+
{ idx_fun := λ _, none,
93+
proper := ⟨classical.arbitrary ι, rfl⟩ }
94+
95+
instance (α ι) [nonempty ι] : inhabited (line α ι) := ⟨diagonal α ι⟩
96+
97+
/-- The type of lines that are only one color except possibly at their endpoints. -/
98+
structure almost_mono {α ι κ : Type*} (C : (ι → option α) → κ) :=
99+
(line : line (option α) ι)
100+
(color : κ)
101+
(has_color : ∀ x : α, C (line (some x)) = color)
102+
103+
instance {α ι κ : Type*} [nonempty ι] [inhabited κ] :
104+
inhabited (almost_mono (λ v : ι → option α, default κ)) :=
105+
⟨{ line := default _,
106+
color := default κ,
107+
has_color := λ _, rfl }⟩
108+
109+
/-- The type of collections of lines such that
110+
- each line is only one color except possibly at its endpoint
111+
- the lines all have the same endpoint
112+
- the colors of the lines are distinct.
113+
Used in the proof `exists_mono_in_high_dimension`. -/
114+
structure color_focused {α ι κ : Type*} (C : (ι → option α) → κ) :=
115+
(lines : multiset (almost_mono C))
116+
(focus : ι → option α)
117+
(is_focused : ∀ p ∈ lines, almost_mono.line p none = focus)
118+
(distinct_colors : (lines.map almost_mono.color).nodup)
119+
120+
instance {α ι κ} (C : (ι → option α) → κ) : inhabited (color_focused C) :=
121+
⟨⟨0, λ _, none, λ _, false.elim, multiset.nodup_zero⟩⟩
122+
123+
/-- A function `f : α → α'` determines a function `line α ι → line α' ι`. For a coordinate `i`,
124+
`l.map f` is the identity at `i` if `l` is, and constantly `f y` if `l` is constantly `y` at `i`. -/
125+
def map {α α' ι} (f : α → α') (l : line α ι) : line α' ι :=
126+
{ idx_fun := λ i, (l.idx_fun i).map f,
127+
proper := ⟨l.proper.some, by rw [l.proper.some_spec, option.map_none'] ⟩ }
128+
129+
/-- A point in `ι → α` and a line in `ι' → α` determine a line in `ι ⊕ ι' → α`. -/
130+
def vertical {α ι ι'} (v : ι → α) (l : line α ι') : line α (ι ⊕ ι') :=
131+
{ idx_fun := sum.elim (some ∘ v) l.idx_fun,
132+
proper := ⟨sum.inr l.proper.some, l.proper.some_spec⟩ }
133+
134+
/-- A line in `ι → α` and a point in `ι' → α` determine a line in `ι ⊕ ι' → α`. -/
135+
def horizontal {α ι ι'} (l : line α ι) (v : ι' → α) : line α (ι ⊕ ι') :=
136+
{ idx_fun := sum.elim l.idx_fun (some ∘ v),
137+
proper := ⟨sum.inl l.proper.some, l.proper.some_spec⟩ }
138+
139+
/-- One line in `ι → α` and one in `ι' → α` together determine a line in `ι ⊕ ι' → α`. -/
140+
def prod {α ι ι'} (l : line α ι) (l' : line α ι') : line α (ι ⊕ ι') :=
141+
{ idx_fun := sum.elim l.idx_fun l'.idx_fun,
142+
proper := ⟨sum.inl l.proper.some, l.proper.some_spec⟩ }
143+
144+
lemma apply {α ι} (l : line α ι) (x : α) : l x = λ i, (l.idx_fun i).get_or_else x := rfl
145+
146+
lemma apply_none {α ι} (l : line α ι) (x : α) (i : ι) (h : l.idx_fun i = none) : l x i = x :=
147+
by simp only [option.get_or_else_none, h, l.apply]
148+
149+
lemma apply_of_ne_none {α ι} (l : line α ι) (x : α) (i : ι) (h : l.idx_fun i ≠ none) :
150+
some (l x i) = l.idx_fun i :=
151+
by rw [l.apply, option.get_or_else_of_ne_none h]
152+
153+
@[simp] lemma map_apply {α α' ι} (f : α → α') (l : line α ι) (x : α) :
154+
l.map f (f x) = f ∘ l x :=
155+
by simp only [line.apply, line.map, option.get_or_else_map]
156+
157+
@[simp] lemma vertical_apply {α ι ι'} (v : ι → α) (l : line α ι') (x : α) :
158+
l.vertical v x = sum.elim v (l x) :=
159+
by { funext i, cases i; refl }
160+
161+
@[simp] lemma horizontal_apply {α ι ι'} (l : line α ι) (v : ι' → α) (x : α) :
162+
l.horizontal v x = sum.elim (l x) v :=
163+
by { funext i, cases i; refl }
164+
165+
@[simp] lemma prod_apply {α ι ι'} (l : line α ι) (l' : line α ι') (x : α) :
166+
l.prod l' x = sum.elim (l x) (l' x) :=
167+
by { funext i, cases i; refl }
168+
169+
@[simp] lemma diagonal_apply {α ι} [nonempty ι] (x : α) :
170+
line.diagonal α ι x = λ i, x :=
171+
by simp_rw [line.apply, line.diagonal, option.get_or_else_none]
172+
173+
/-- The Hales-Jewett theorem. This version has a restriction on universe levels which is necessary
174+
for the proof. See `exists_mono_in_high_dimension` for a fully universe-polymorphic version. -/
175+
private theorem exists_mono_in_high_dimension' :
176+
∀ (α : Type u) [fintype α] (κ : Type (max v u)) [fintype κ],
177+
∃ (ι : Type) [fintype ι], ∀ C : (ι → α) → κ, ∃ l : line α ι, l.is_mono C :=
178+
-- The proof proceeds by induction on `α`.
179+
fintype.induction_empty_option
180+
-- We have to show that the theorem is invariant under `α ≃ α'` for the induction to work.
181+
(λ α α' e, forall_imp $ λ κ, forall_imp $ λ _, Exists.imp $ λ ι, Exists.imp $ λ _ h C,
182+
let ⟨l, c, lc⟩ := h (λ v, C (e ∘ v)) in
183+
⟨l.map e, c, e.forall_congr_left.mp $ λ x, by rw [←lc x, line.map_apply]⟩)
184+
begin -- This deals with the degenerate case where `α` is empty.
185+
introsI κ _,
186+
by_cases h : nonempty κ,
187+
{ resetI, exact ⟨unit, infer_instance, λ C, ⟨default _, classical.arbitrary _, pempty.rec _⟩⟩, },
188+
{ exact ⟨empty, infer_instance, λ C, (h ⟨C (empty.rec _)⟩).elim⟩, }
189+
end
190+
begin -- Now we have to show that the theorem holds for `option α` if it holds for `α`.
191+
introsI α _ ihα κ _,
192+
-- Later we'll need `α` to be nonempty. So we first deal with the trivial case where `α` is empty.
193+
-- Then `option α` has only one element, so any line is monochromatic.
194+
by_cases h : nonempty α,
195+
work_on_goal 1 { refine ⟨unit, infer_instance, λ C, ⟨diagonal _ _, C (λ _, none), _⟩⟩,
196+
rintros (_ | ⟨a⟩), refl, exact (h ⟨a⟩).elim, },
197+
-- The key idea is to show that for every `r`, in high dimension we can either find
198+
-- `r` color focused lines or a monochromatic line.
199+
suffices key : ∀ r : ℕ, ∃ (ι : Type) [fintype ι], ∀ C : (ι → (option α)) → κ,
200+
(∃ s : color_focused C, s.lines.card = r) ∨ (∃ l, is_mono C l),
201+
-- Given the key claim, we simply take `r = |κ| + 1`. We cannot have this many distinct colors so
202+
-- we must be in the second case, where there is a monochromatic line.
203+
{ obtain ⟨ι, _inst, hι⟩ := key (fintype.card κ + 1),
204+
refine ⟨ι, _inst, λ C, (hι C).resolve_left _⟩,
205+
rintro ⟨s, sr⟩,
206+
apply nat.not_succ_le_self (fintype.card κ),
207+
rw [←nat.add_one, ←sr, ←multiset.card_map, ←finset.card_mk],
208+
exact finset.card_le_univ ⟨_, s.distinct_colors⟩ },
209+
-- We now prove the key claim, by induction on `r`.
210+
intro r,
211+
induction r with r ihr,
212+
-- The base case `r = 0` is trivial as the empty collection is color-focused.
213+
{ exact ⟨empty, infer_instance, λ C, or.inl ⟨default _, multiset.card_zero⟩⟩, },
214+
-- Supposing the key claim holds for `r`, we need to show it for `r+1`. First pick a high enough
215+
-- dimension `ι` for `r`.
216+
obtain ⟨ι, _inst, hι⟩ := ihr,
217+
resetI,
218+
-- Then since the theorem holds for `α` with any number of colors, pick a dimension `ι'` such that
219+
-- `ι' → α` always has a monochromatic line whenever it is `(ι → option α) → κ`-colored.
220+
specialize ihα ((ι → option α) → κ),
221+
obtain ⟨ι', _inst, hι'⟩ := ihα,
222+
resetI,
223+
-- We claim that `ι ⊕ ι'` works for `option α` and `κ`-coloring.
224+
refine ⟨ι ⊕ ι', infer_instance, _⟩,
225+
intro C,
226+
-- A `κ`-coloring of `ι ⊕ ι' → option α` induces an `(ι → option α) → κ`-coloring of `ι' → α`.
227+
specialize hι' (λ v' v, C (sum.elim v (some ∘ v'))),
228+
-- By choice of `ι'` this coloring has a monochromatic line `l'` with color class `C'`, where
229+
-- `C'` is a `κ`-coloring of `ι → α`.
230+
obtain ⟨l', C', hl'⟩ := hι',
231+
-- If `C'` has a monochromatic line, then so does `C`. We use this in two places below.
232+
have mono_of_mono : (∃ l, is_mono C' l) → (∃ l, is_mono C l),
233+
{ rintro ⟨l, c, hl⟩,
234+
refine ⟨l.horizontal (some ∘ l' (classical.arbitrary α)), c, λ x, _⟩,
235+
rw [line.horizontal_apply, ←hl, ←hl'], },
236+
-- By choice of `ι`, `C'` either has `r` color-focused lines or a monochromatic line.
237+
specialize hι C',
238+
rcases hι with ⟨s, sr⟩ | _,
239+
-- By above, we are done if `C'` has a monochromatic line.
240+
work_on_goal 1 { exact or.inr (mono_of_mono hι) },
241+
-- Here we assume `C'` has `r` color focused lines. We split into cases depending on whether one of
242+
-- these `r` lines has the same color as the focus point.
243+
by_cases h : ∃ p ∈ s.lines, (p : almost_mono _).color = C' s.focus,
244+
-- If so then this is a `C'`-monochromatic line and we are done.
245+
{ obtain ⟨p, p_mem, hp⟩ := h,
246+
refine or.inr (mono_of_mono ⟨p.line, p.color, _⟩),
247+
rintro (_ | _), rw [hp, s.is_focused p p_mem], apply p.has_color, },
248+
-- If not, we get `r+1` color focused lines by taking the product of the `r` lines with `l'` and
249+
-- adding to this the vertical line obtained by the focus point and `l`.
250+
refine or.inl ⟨⟨(s.lines.map _).cons ⟨(l'.map some).vertical s.focus, C' s.focus, λ x, _⟩,
251+
sum.elim s.focus (l'.map some none), _, _⟩, _⟩,
252+
-- The vertical line is almost monochromatic.
253+
{ rw [vertical_apply, ←congr_fun (hl' x), line.map_apply], },
254+
{ refine λ p, ⟨p.line.prod (l'.map some), p.color, λ x, _⟩,
255+
-- The product lines are almost monochromatic.
256+
rw [line.prod_apply, line.map_apply, ←p.has_color, ←congr_fun (hl' x)], },
257+
-- Our `r+1` lines have the same endpoint.
258+
{ simp_rw [multiset.mem_cons, multiset.mem_map],
259+
rintros _ (rfl | ⟨q, hq, rfl⟩),
260+
{ rw line.vertical_apply, },
261+
{ rw [line.prod_apply, s.is_focused q hq], }, },
262+
-- Our `r+1` lines have distinct colors (this is why we needed to split into cases above).
263+
{ rw [multiset.map_cons, multiset.map_map, multiset.nodup_cons, multiset.mem_map],
264+
exact ⟨λ ⟨q, hq, he⟩, h ⟨q, hq, he⟩, s.distinct_colors⟩, },
265+
-- Finally, we really do have `r+1` lines!
266+
{ rw [multiset.card_cons, multiset.card_map, sr], },
267+
end
268+
269+
/-- The Hales-Jewett theorem: for any finite types `α` and `κ`, there exists a finite type `ι` such
270+
that whenever the hypercube `ι → α` is `κ`-colored, there is a monochromatic combinatorial line. -/
271+
theorem exists_mono_in_high_dimension (α : Type u) [fintype α] (κ : Type v) [fintype κ] :
272+
∃ (ι : Type) [fintype ι], ∀ C : (ι → α) → κ, ∃ l : line α ι, l.is_mono C :=
273+
let ⟨ι, ιfin, hι⟩ := exists_mono_in_high_dimension' α (ulift κ)
274+
in ⟨ι, ιfin, λ C, let ⟨l, c, hc⟩ := hι (ulift.up ∘ C) in ⟨l, c.down, λ x, by rw ←hc⟩ ⟩
275+
276+
end line
277+
278+
/-- A generalization of Van der Waerden's theorem: if `M` is a finitely colored commutative
279+
monoid, and `S` is a finite subset, then there exists a monochromatic homothetic copy of `S`. -/
280+
theorem exists_mono_homothetic_copy
281+
{M κ} [add_comm_monoid M] (S : finset M) [fintype κ] (C : M → κ) :
282+
∃ (a > 0) (b : M) (c : κ), ∀ s ∈ S, C (a • s + b) = c :=
283+
begin
284+
obtain ⟨ι, _inst, hι⟩ := line.exists_mono_in_high_dimension S κ,
285+
resetI,
286+
specialize hι (λ v, C $ ∑ i, v i),
287+
obtain ⟨l, c, hl⟩ := hι,
288+
set s : finset ι := { i ∈ finset.univ | l.idx_fun i = none } with hs,
289+
refine ⟨s.card, finset.card_pos.mpr ⟨l.proper.some, _⟩,
290+
∑ i in sᶜ, ((l.idx_fun i).map coe).get_or_else 0, c, _⟩,
291+
{ rw [hs, finset.sep_def, finset.mem_filter], exact ⟨finset.mem_univ _, l.proper.some_spec⟩, },
292+
intros x xs,
293+
rw ←hl ⟨x, xs⟩,
294+
clear hl, congr,
295+
rw ←finset.sum_add_sum_compl s,
296+
congr' 1,
297+
{ rw ←finset.sum_const,
298+
apply finset.sum_congr rfl,
299+
intros i hi,
300+
rw [hs, finset.sep_def, finset.mem_filter] at hi,
301+
rw [l.apply_none _ _ hi.right, subtype.coe_mk], },
302+
{ apply finset.sum_congr rfl,
303+
intros i hi,
304+
rw [hs, finset.sep_def, finset.compl_filter, finset.mem_filter] at hi,
305+
obtain ⟨y, hy⟩ := option.ne_none_iff_exists.mp hi.right,
306+
simp_rw [line.apply, ←hy, option.map_some', option.get_or_else_some], },
307+
end
308+
309+
end combinatorics

src/data/list/basic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2543,7 +2543,7 @@ end
25432543
@[to_additive]
25442544
lemma head_mul_tail_prod' [monoid α] (L : list α) :
25452545
(L.nth 0).get_or_else 1 * L.tail.prod = L.prod :=
2546-
by { cases L, { simp, refl, }, { simp, }, }
2546+
by cases L; simp
25472547

25482548
lemma head_add_tail_sum (L : list ℕ) : L.head + L.tail.sum = L.sum :=
25492549
by { cases L, { simp, refl, }, { simp, }, }

src/data/option/basic.lean

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ theorem get_of_mem {a : α} : ∀ {o : option α} (h : is_some o), a ∈ o → o
6060

6161
@[simp] lemma get_or_else_some (x y : α) : option.get_or_else (some x) y = x := rfl
6262

63+
@[simp] lemma get_or_else_none (x : α) : option.get_or_else none x = x := rfl
64+
6365
@[simp] lemma get_or_else_coe (x y : α) : option.get_or_else ↑x y = x := rfl
6466

6567
lemma get_or_else_of_ne_none {x : option α} (hx : x ≠ none) (y : α) : some (x.get_or_else y) = x :=
@@ -409,6 +411,10 @@ def cases_on' : option α → β → (α → β) → β
409411
cases_on' o (f none) (f ∘ coe) = f o :=
410412
by cases o; refl
411413

414+
@[simp] lemma get_or_else_map (f : α → β) (x : α) (o : option α) :
415+
get_or_else (o.map f) (f x) = f (get_or_else o x) :=
416+
by cases o; refl
417+
412418
section
413419
open_locale classical
414420

0 commit comments

Comments
 (0)