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

Commit b41277c

Browse files
kim-emmergify[bot]
authored andcommitted
feat(set_theory/game): the theory of combinatorial games (#1274)
* correcting definition of addition, and splitting content into two files, one about games, one about surreals * add_le_zero_of_le_zero, but without well-foundedness * progress * Mario's well-foundedness proof * getting there! * success! * minor * almost there * progress * off to write some tactics * not quite there * hmmm * getting there! * domineering is hard * removing unneeded theorems * cleanup * add_semigroup surreal * cleanup * short proof * cleaning up * remove equiv_rw * move lemmas about pempty to logic.basic * slightly more comments; still lots to go * documentation * finishing documentation * typo * Update src/logic/basic.lean Co-Authored-By: Rob Lewis <Rob.y.lewis@gmail.com> * fix references * oops * change statement of equiv.refl_symm * more card_erase lemmas; golf domineering proofs * style changes * fix comment * fixes after Reid's review * some improvements * golfing * subsingleton short * diagnosing decidable * hmmmhmmm * computational domineering * fix missing proofs (need golfing?) * minor * short_of_relabelling * abbreviating * various minor * removing short games and domineering from this PR * style / proof simplification / golfing * some minor golfing * adding Reid to the author line * add @[simp] * adding two lemmas characterising the order relation * separating out game and pgame, and discarding lame lemmas * comment * fixes
1 parent 19a246c commit b41277c

File tree

10 files changed

+1429
-228
lines changed

10 files changed

+1429
-228
lines changed

docs/references.bib

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44
% %
55
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66
7+
@article {MR1167694,
8+
AUTHOR = {Blass, Andreas},
9+
TITLE = {A game semantics for linear logic},
10+
JOURNAL = {Ann. Pure Appl. Logic},
11+
FJOURNAL = {Annals of Pure and Applied Logic},
12+
VOLUME = {56},
13+
YEAR = {1992},
14+
NUMBER = {1-3},
15+
PAGES = {183--220},
16+
ISSN = {0168-0072},
17+
MRCLASS = {03B70 (68Q55)},
18+
MRNUMBER = {1167694},
19+
MRREVIEWER = {Fangmin Song},
20+
DOI = {10.1016/0168-0072(92)90073-9},
21+
URL = {https://doi.org/10.1016/0168-0072(92)90073-9},
22+
}
23+
724
@book {bourbaki1966,
825
AUTHOR = {Bourbaki, Nicolas},
926
TITLE = {Elements of mathematics. {G}eneral topology. {P}art 1},
@@ -15,6 +32,18 @@ @book {bourbaki1966
1532
MRNUMBER = {0205210},
1633
}
1734

35+
@book {conway2001,
36+
AUTHOR = {Conway, J. H.},
37+
TITLE = {On numbers and games},
38+
EDITION = {Second},
39+
PUBLISHER = {A K Peters, Ltd., Natick, MA},
40+
YEAR = {2001},
41+
PAGES = {xii+242},
42+
ISBN = {1-56881-127-6},
43+
MRCLASS = {00A08 (05-01 91A05)},
44+
MRNUMBER = {1803095},
45+
}
46+
1847
@book {gouvea1997,
1948
AUTHOR = {Gouv\^{e}a, Fernando Q.},
2049
TITLE = {{$p$}-adic numbers},
@@ -48,9 +77,20 @@ @book {james1999
4877
URL = {https://doi.org/10.1007/978-1-4471-3994-2},
4978
}
5079

80+
@article {joyal1977,
81+
author = {André Joyal},
82+
title = {Remarques sur la théorie des jeux à deux personnes},
83+
journal = {Gazette des Sciences Mathematiques du Québec},
84+
volume = {1},
85+
number = {4},
86+
pages = {46--52},
87+
year = {1977},
88+
note = {(English translation at https://bosker.files.wordpress.com/2010/12/joyal-games.pdf)}
89+
}
90+
5191
@inproceedings{lewis2019,
5292
author = {Lewis, Robert Y.},
53-
title = {A Formal Proof of Hensel\&\#39;s Lemma over the P-adic Integers},
93+
title = {A Formal Proof of {H}ensel's Lemma over the {$p$}-adic Integers},
5494
booktitle = {Proceedings of the 8th ACM SIGPLAN International Conference on Certified Programs and Proofs},
5595
series = {CPP 2019},
5696
year = {2019},
@@ -63,7 +103,7 @@ @inproceedings{lewis2019
63103
acmid = {3294089},
64104
publisher = {ACM},
65105
address = {New York, NY, USA},
66-
keywords = {Hensel\&\#39;s lemma, Lean, formal proof, p-adic},
106+
keywords = {Hensel's lemma, Lean, formal proof, p-adic},
67107
}
68108

69109
@book {riehl2017,

src/algebra/ordered_group.lean

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,29 @@ by simpa [add_comm] using @with_top.add_lt_add_iff_left _ _ a b c
470470
end ordered_cancel_comm_monoid
471471

472472
section ordered_comm_group
473+
474+
/--
475+
The `add_lt_add_left` field of `ordered_comm_group` is redundant, but it is in core so
476+
we can't remove it for now. This alternative constructor is the best we can do.
477+
-/
478+
def ordered_comm_group.mk' {α : Type u} [add_comm_group α] [partial_order α]
479+
(add_le_add_left : ∀ a b : α, a ≤ b → ∀ c : α, c + a ≤ c + b) :
480+
ordered_comm_group α :=
481+
{ add_le_add_left := add_le_add_left,
482+
add_lt_add_left := λ a b h c,
483+
begin
484+
rw lt_iff_le_not_le at h,
485+
rw lt_iff_le_not_le,
486+
split,
487+
{ apply add_le_add_left _ _ h.1 },
488+
{ intro w,
489+
replace w : -c + (c + b) ≤ -c + (c + a) := add_le_add_left _ _ w _,
490+
simp only [add_zero, add_comm, add_left_neg, add_left_comm] at w,
491+
exact h.2 w },
492+
end,
493+
..(by apply_instance : add_comm_group α),
494+
..(by apply_instance : partial_order α) }
495+
473496
variables [ordered_comm_group α] {a b c : α}
474497

475498
lemma neg_neg_iff_pos {α : Type} [_inst_1 : ordered_comm_group α] {a : α} : -a < 00 < a :=

src/data/equiv/basic.lean

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ lemma eq_symm_apply {α β} (e : α ≃ β) {x y} : y = e.symm x ↔ e y = x :=
112112

113113
@[simp] theorem trans_refl (e : α ≃ β) : e.trans (equiv.refl β) = e := by { cases e, refl }
114114

115+
@[simp] theorem refl_symm : (equiv.refl α).symm = equiv.refl α := rfl
116+
115117
@[simp] theorem refl_trans (e : α ≃ β) : (equiv.refl α).trans e = e := by { cases e, refl }
116118

117119
@[simp] theorem symm_trans (e : α ≃ β) : e.symm.trans e = equiv.refl β := ext _ _ (by simp)
@@ -348,6 +350,10 @@ by { cases e₁, cases e₂, refl }
348350
sum_congr e₁ e₂ (inr b) = inr (e₂ b) :=
349351
by { cases e₁, cases e₂, refl }
350352

353+
@[simp] lemma sum_congr_symm {α β γ δ : Type u} (e : α ≃ β) (f : γ ≃ δ) (x) :
354+
(equiv.sum_congr e f).symm x = (equiv.sum_congr (e.symm) (f.symm)) x :=
355+
by { cases e, cases f, cases x; refl }
356+
351357
def bool_equiv_punit_sum_punit : bool ≃ punit.{u+1} ⊕ punit.{v+1} :=
352358
⟨λ b, cond b (inr punit.star) (inl punit.star),
353359
λ s, sum.rec_on s (λ_, ff) (λ_, tt),

src/data/finset.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,9 @@ card_eq_zero.trans val_eq_zero
10021002
theorem card_pos {s : finset α} : 0 < card s ↔ s ≠ ∅ :=
10031003
pos_iff_ne_zero.trans $ not_congr card_eq_zero
10041004

1005+
theorem card_ne_zero_of_mem {s : finset α} {a : α} (h : a ∈ s) : card s ≠ 0 :=
1006+
(not_congr card_eq_zero).2 (ne_empty_of_mem h)
1007+
10051008
theorem card_eq_one {s : finset α} : s.card = 1 ↔ ∃ a, s = finset.singleton a :=
10061009
by cases s; simp [multiset.card_eq_one, finset.singleton, finset.card]
10071010

@@ -1018,6 +1021,10 @@ rw [card_insert_of_not_mem h]]
10181021

10191022
theorem card_erase_of_mem [decidable_eq α] {a : α} {s : finset α} : a ∈ s → card (erase s a) = pred (card s) := card_erase_of_mem
10201023

1024+
theorem card_erase_lt_of_mem [decidable_eq α] {a : α} {s : finset α} : a ∈ s → card (erase s a) < card s := card_erase_lt_of_mem
1025+
1026+
theorem card_erase_le [decidable_eq α] {a : α} {s : finset α} : card (erase s a) ≤ card s := card_erase_le
1027+
10211028
@[simp] theorem card_range (n : ℕ) : card (range n) = n := card_range n
10221029

10231030
@[simp] theorem card_attach {s : finset α} : card (attach s) = card s := multiset.card_attach

src/data/multiset.lean

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,6 @@ theorem le_cons_erase (s : multiset α) (a : α) : s ≤ a :: s.erase a :=
534534
if h : a ∈ s then le_of_eq (cons_erase h).symm
535535
else by rw erase_of_not_mem h; apply le_cons_self
536536

537-
@[simp] theorem card_erase_of_mem {a : α} {s : multiset α} : a ∈ s → card (s.erase a) = pred (card s) :=
538-
quot.induction_on s $ λ l, length_erase_of_mem
539-
540537
theorem erase_add_left_pos {a : α} {s : multiset α} (t) : a ∈ s → (s + t).erase a = s.erase a + t :=
541538
quotient.induction_on₂ s t $ λ l₁ l₂ h, congr_arg coe $ erase_append_left l₂ h
542539

@@ -577,6 +574,15 @@ theorem erase_le_iff_le_cons {s t : multiset α} {a : α} : s.erase a ≤ t ↔
577574
then by rw ← cons_erase m at h; exact (cons_le_cons_iff _).1 h
578575
else le_trans (erase_le _ _) ((le_cons_of_not_mem m).1 h)⟩
579576

577+
@[simp] theorem card_erase_of_mem {a : α} {s : multiset α} : a ∈ s → card (s.erase a) = pred (card s) :=
578+
quot.induction_on s $ λ l, length_erase_of_mem
579+
580+
theorem card_erase_lt_of_mem {a : α} {s : multiset α} : a ∈ s → card (s.erase a) < card s :=
581+
λ h, card_lt_of_lt (erase_lt.mpr h)
582+
583+
theorem card_erase_le {a : α} {s : multiset α} : card (s.erase a) ≤ card s :=
584+
card_le_of_le (erase_le a s)
585+
580586
end erase
581587

582588
@[simp] theorem coe_reverse (l : list α) : (reverse l : multiset α) = l :=

src/linear_algebra/dimension.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ cardinal.lift_inj.1 $ hb.mk_eq_dim.symm.trans (f.is_basis hb).mk_eq_dim
115115

116116
@[simp] lemma dim_bot : dim α (⊥ : submodule α β) = 0 :=
117117
by letI := classical.dec_eq β;
118-
rw [← cardinal.lift_inj, ← (@is_basis_empty_bot pempty α β _ _ _ _ _ _ nonempty_pempty).mk_eq_dim,
118+
rw [← cardinal.lift_inj, ← (@is_basis_empty_bot pempty α β _ _ _ _ _ _ not_nonempty_pempty).mk_eq_dim,
119119
cardinal.mk_pempty]
120120

121121
@[simp] lemma dim_top : dim α (⊤ : submodule α β) = dim α β :=

src/logic/basic.lean

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@
22
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Jeremy Avigad, Leonardo de Moura
5+
-/
56

7+
/-!
68
Theorems that require decidability hypotheses are in the namespace "decidable".
79
Classical versions are in the namespace "classical".
810
911
Note: in the presence of automation, this whole file may be unnecessary. On the other hand,
1012
maybe it is useful for writing automation.
1113
-/
1214

13-
/-
14-
miscellany
1515

16-
TODO: move elsewhere
17-
-/
1816

1917
section miscellany
2018

@@ -67,15 +65,21 @@ def pempty.elim {C : Sort*} : pempty → C.
6765

6866
instance subsingleton_pempty : subsingleton pempty := ⟨λa, a.elim⟩
6967

68+
@[simp] lemma not_nonempty_pempty : ¬ nonempty pempty :=
69+
assume ⟨h⟩, h.elim
70+
71+
@[simp] theorem forall_pempty {P : pempty → Prop} : (∀ x : pempty, P x) ↔ true :=
72+
⟨λ h, trivial, λ h x, by cases x⟩
73+
74+
@[simp] theorem exists_pempty {P : pempty → Prop} : (∃ x : pempty, P x) ↔ false :=
75+
⟨λ h, by { cases h with w, cases w }, false.elim⟩
76+
7077
lemma congr_arg_heq {α} {β : α → Sort*} (f : ∀ a, β a) : ∀ {a₁ a₂ : α}, a₁ = a₂ → f a₁ == f a₂
7178
| a _ rfl := heq.rfl
7279

7380
lemma plift.down_inj {α : Sort*} : ∀ (a b : plift α), a.down = b.down → a = b
7481
| ⟨a⟩ ⟨b⟩ rfl := rfl
7582

76-
@[simp] lemma nonempty_pempty : ¬ nonempty pempty :=
77-
assume ⟨h⟩, h.elim
78-
7983
-- missing [symm] attribute for ne in core.
8084
attribute [symm] ne.symm
8185

src/set_theory/game.lean

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/-
2+
Copyright (c) 2019 Mario Carneiro. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Scott Morrison
5+
-/
6+
import set_theory.pgame
7+
8+
/-!
9+
# Combinatorial games.
10+
11+
In this file we define the quotient of pre-games by the equivalence relation `p ≈ q ↔ p ≤ q ∧ q ≤
12+
p`, and construct an instance `add_comm_group game`, as well as an instance `partial_order game`
13+
(although note carefully the warning that the `<` field in this instance is not the usual relation
14+
on combinatorial games).
15+
-/
16+
17+
universes u
18+
19+
local infix ` ≈ ` := pgame.equiv
20+
21+
instance pgame.setoid : setoid pgame :=
22+
⟨λ x y, x ≈ y,
23+
λ x, pgame.equiv_refl _,
24+
λ x y, pgame.equiv_symm,
25+
λ x y z, pgame.equiv_trans⟩
26+
27+
/-- The type of combinatorial games. In ZFC, a combinatorial game is constructed from
28+
two sets of combinatorial games that have been constructed at an earlier
29+
stage. To do this in type theory, we say that a combinatorial pre-game is built
30+
inductively from two families of combinatorial games indexed over any type
31+
in Type u. The resulting type `pgame.{u}` lives in `Type (u+1)`,
32+
reflecting that it is a proper class in ZFC.
33+
A combinatorial game is then constructed by quotienting by the equivalence
34+
`x ≈ y ↔ x ≤ y ∧ y ≤ x`. -/
35+
def game := quotient pgame.setoid
36+
37+
open pgame
38+
39+
namespace game
40+
41+
/-- The relation `x ≤ y` on games. -/
42+
def le : game → game → Prop :=
43+
quotient.lift₂ (λ x y, x ≤ y) (λ x₁ y₁ x₂ y₂ hx hy, propext (le_congr hx hy))
44+
45+
instance : has_le game :=
46+
{ le := le }
47+
48+
@[refl] theorem le_refl : ∀ x : game, x ≤ x :=
49+
by { rintro ⟨x⟩, apply pgame.le_refl }
50+
@[trans] theorem le_trans : ∀ x y z : game, x ≤ y → y ≤ z → x ≤ z :=
51+
by { rintro ⟨x⟩ ⟨y⟩ ⟨z⟩, apply pgame.le_trans }
52+
theorem le_antisymm : ∀ x y : game, x ≤ y → y ≤ x → x = y :=
53+
by { rintro ⟨x⟩ ⟨y⟩ h₁ h₂, apply quot.sound, exact ⟨h₁, h₂⟩ }
54+
55+
/-- The relation `x < y` on games. -/
56+
-- We don't yet make this into an instance, because it will conflict with the (incorrect) notion
57+
-- of `<` provided by `partial_order` later.
58+
def lt : game → game → Prop :=
59+
quotient.lift₂ (λ x y, x < y) (λ x₁ y₁ x₂ y₂ hx hy, propext (lt_congr hx hy))
60+
61+
theorem not_le : ∀ {x y : game}, ¬ (x ≤ y) ↔ (lt y x) :=
62+
by { rintro ⟨x⟩ ⟨y⟩, exact not_le }
63+
64+
instance : has_zero game := ⟨⟦0⟧⟩
65+
instance : has_one game := ⟨⟦1⟧⟩
66+
67+
/-- The negation of `{L | R}` is `{-R | -L}`. -/
68+
def neg : game → game :=
69+
quot.lift (λ x, ⟦-x⟧) (λ x y h, quot.sound (@neg_congr x y h))
70+
71+
instance : has_neg game :=
72+
{ neg := neg }
73+
74+
/-- The sum of `x = {xL | xR}` and `y = {yL | yR}` is `{xL + y, x + yL | xR + y, x + yR}`. -/
75+
def add : game → game → game :=
76+
quotient.lift₂ (λ x y : pgame, ⟦x + y⟧) (λ x₁ y₁ x₂ y₂ hx hy, quot.sound (pgame.add_congr hx hy))
77+
78+
instance : has_add game := ⟨add⟩
79+
80+
theorem add_assoc : ∀ (x y z : game), (x + y) + z = x + (y + z) :=
81+
begin
82+
rintros ⟨x⟩ ⟨y⟩ ⟨z⟩,
83+
apply quot.sound,
84+
exact add_assoc_equiv
85+
end
86+
87+
instance : add_semigroup game.{u} :=
88+
{ add_assoc := add_assoc,
89+
..game.has_add }
90+
91+
theorem add_zero : ∀ (x : game), x + 0 = x :=
92+
begin
93+
rintro ⟨x⟩,
94+
apply quot.sound,
95+
apply add_zero_equiv
96+
end
97+
theorem zero_add : ∀ (x : game), 0 + x = x :=
98+
begin
99+
rintro ⟨x⟩,
100+
apply quot.sound,
101+
apply zero_add_equiv
102+
end
103+
104+
instance : add_monoid game :=
105+
{ add_zero := add_zero,
106+
zero_add := zero_add,
107+
..game.has_zero,
108+
..game.add_semigroup }
109+
110+
theorem add_left_neg : ∀ (x : game), (-x) + x = 0 :=
111+
begin
112+
rintro ⟨x⟩,
113+
apply quot.sound,
114+
apply add_left_neg_equiv
115+
end
116+
117+
instance : add_group game :=
118+
{ add_left_neg := add_left_neg,
119+
..game.has_neg,
120+
..game.add_monoid }
121+
122+
theorem add_comm : ∀ (x y : game), x + y = y + x :=
123+
begin
124+
rintros ⟨x⟩ ⟨y⟩,
125+
apply quot.sound,
126+
exact add_comm_equiv
127+
end
128+
129+
instance : add_comm_semigroup game :=
130+
{ add_comm := add_comm,
131+
..game.add_semigroup }
132+
133+
instance : add_comm_group game :=
134+
{ ..game.add_comm_semigroup,
135+
..game.add_group }
136+
137+
theorem add_le_add_left : ∀ (a b : game), a ≤ b → ∀ (c : game), c + a ≤ c + b :=
138+
begin rintro ⟨a⟩ ⟨b⟩ h ⟨c⟩, apply pgame.add_le_add_left h, end
139+
140+
-- While it is very tempting to define a `partial_order` on games, and prove
141+
-- that games form an `ordered_comm_group`, it is a bit dangerous.
142+
143+
-- The relations `≤` and `<` on games do not satisfy
144+
-- `lt_iff_le_not_le : ∀ a b : α, a < b ↔ (a ≤ b ∧ ¬ b ≤ a)`
145+
-- (Consider `a = 0`, `b = star`.)
146+
-- (`lt_iff_le_not_le` is satisfied by surreal numbers, however.)
147+
-- Thus we can not use `<` when defining a `partial_order`.
148+
149+
-- Because of this issue, we define the `partial_order` and `ordered_comm_group` instances,
150+
-- but do not actually mark them as instances, for safety.
151+
152+
/-- The `<` operation provided by this partial order is not the usual `<` on games! -/
153+
def game_partial_order : partial_order game :=
154+
{ le_refl := le_refl,
155+
le_trans := le_trans,
156+
le_antisymm := le_antisymm,
157+
..game.has_le }
158+
159+
local attribute [instance] game_partial_order
160+
161+
/-- The `<` operation provided by this `ordered_comm_group` is not the usual `<` on games! -/
162+
def ordered_comm_group_game : ordered_comm_group game :=
163+
ordered_comm_group.mk' add_le_add_left
164+
165+
end game

0 commit comments

Comments
 (0)