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

Commit 84d47a0

Browse files
committed
refactor(set_theory/game): make impartial a class (#3974)
* Misc. style cleanups and code golf * Changed naming and namespace to adhere more closely to the naming convention * Changed `impartial` to be a `class`. I am aware that @semorrison explicitly requested not to make `impartial` a class in the #3855, but after working with the definition a bit I concluded that making it a class is worth it, simply because writing `impartial_add (nim_impartial _) (nim_impartial _)` gets annoying quite quickly, but also because you tend to get goal states of the form `Grundy_value _ = Grundy_value _`. By making `impartial` a class and making the game argument explicit, these goal states look like `grundy_value G = grundy_value H`, which is much nicer to work with.
1 parent ea177c2 commit 84d47a0

File tree

3 files changed

+160
-216
lines changed

3 files changed

+160
-216
lines changed

src/set_theory/game/impartial.lean

Lines changed: 82 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import tactic.equiv_rw
1010
universe u
1111

1212
/-!
13-
# Basic deinitions about impartial (pre-)games
13+
# Basic definitions about impartial (pre-)games
1414
1515
We will define an impartial game, one in which left and right can make exactly the same moves.
1616
Our definition differs slightly by saying that the game is always equivalent to its negative,
@@ -22,12 +22,10 @@ namespace pgame
2222

2323
local infix ` ≈ ` := equiv
2424

25-
/-- The definiton for a impartial game, defined using Conway induction -/
26-
def impartial : pgame → Prop
25+
/-- The definition for a impartial game, defined using Conway induction -/
26+
@[class] def impartial : pgame → Prop
2727
| G := G ≈ -G ∧ (∀ i, impartial (G.move_left i)) ∧ (∀ j, impartial (G.move_right j))
28-
using_well_founded {dec_tac := pgame_wf_tac}
29-
30-
lemma zero_impartial : impartial 0 := by tidy
28+
using_well_founded { dec_tac := pgame_wf_tac }
3129

3230
lemma impartial_def {G : pgame} :
3331
G.impartial ↔ G ≈ -G ∧ (∀ i, impartial (G.move_left i)) ∧ (∀ j, impartial (G.move_right j)) :=
@@ -41,204 +39,166 @@ begin
4139
exact hi }
4240
end
4341

44-
lemma impartial_neg_equiv_self {G : pgame} (h : G.impartial) : G ≈ -G := (impartial_def.1 h).1
42+
namespace impartial
43+
44+
instance impartial_zero : impartial 0 := by tidy
45+
46+
lemma neg_equiv_self (G : pgame) [h : G.impartial] : G ≈ -G := (impartial_def.1 h).1
4547

46-
lemma impartial_move_left_impartial {G : pgame} (h : G.impartial) (i : G.left_moves) :
47-
impartial (G.move_left i) :=
48+
instance move_left_impartial {G : pgame} [h : G.impartial] (i : G.left_moves) :
49+
(G.move_left i).impartial :=
4850
(impartial_def.1 h).2.1 i
4951

50-
lemma impartial_move_right_impartial {G : pgame} (h : G.impartial) (j : G.right_moves) :
51-
impartial (G.move_right j) :=
52+
instance move_right_impartial {G : pgame} [h : G.impartial] (j : G.right_moves) :
53+
(G.move_right j).impartial :=
5254
(impartial_def.1 h).2.2 j
5355

54-
lemma impartial_add : ∀ {G H : pgame}, G.impartialH.impartial (G + H).impartial
56+
instance impartial_add : ∀ (G H : pgame) [G.impartial] [H.impartial], (G + H).impartial
5557
| G H :=
5658
begin
57-
intros hG hH,
59+
introsI hG hH,
5860
rw impartial_def,
5961
split,
6062
{ apply equiv_trans _ (equiv_of_relabelling (neg_add_relabelling G H)).symm,
61-
apply add_congr,
62-
exact impartial_neg_equiv_self hG,
63-
exact impartial_neg_equiv_self hH },
63+
exact add_congr (neg_equiv_self _) (neg_equiv_self _) },
6464
split,
65+
all_goals
6566
{ intro i,
66-
equiv_rw pgame.left_moves_add G H at i,
67-
cases i with iG iH,
68-
{ rw add_move_left_inl,
69-
exact impartial_add (impartial_move_left_impartial hG _) hH },
70-
{ rw add_move_left_inr,
71-
exact impartial_add hG (impartial_move_left_impartial hH _) } },
72-
{ intro j,
73-
equiv_rw pgame.right_moves_add G H at j,
74-
cases j with jG jH,
75-
{ rw add_move_right_inl,
76-
exact impartial_add (impartial_move_right_impartial hG _) hH },
77-
{ rw add_move_right_inr,
78-
exact impartial_add hG (impartial_move_right_impartial hH _) } }
67+
equiv_rw pgame.left_moves_add G H at i <|> equiv_rw pgame.right_moves_add G H at i,
68+
cases i },
69+
all_goals
70+
{ simp only [add_move_left_inl, add_move_right_inl, add_move_left_inr, add_move_right_inr],
71+
exact impartial_add _ _ }
7972
end
80-
using_well_founded {dec_tac := pgame_wf_tac}
73+
using_well_founded { dec_tac := pgame_wf_tac }
8174

82-
lemma impartial_neg : ∀ {G : pgame}, G.impartial (-G).impartial
75+
instance impartial_neg : ∀ (G : pgame) [G.impartial], (-G).impartial
8376
| G :=
8477
begin
85-
intro hG,
78+
introI hG,
8679
rw impartial_def,
8780
split,
8881
{ rw neg_neg,
8982
symmetry,
90-
exact impartial_neg_equiv_self hG },
83+
exact neg_equiv_self G },
9184
split,
85+
all_goals
9286
{ intro i,
93-
equiv_rw G.left_moves_neg at i,
94-
rw move_left_left_moves_neg_symm,
95-
exact impartial_neg (impartial_move_right_impartial hG _) },
96-
{ intro j,
97-
equiv_rw G.right_moves_neg at j,
98-
rw move_right_right_moves_neg_symm,
99-
exact impartial_neg (impartial_move_left_impartial hG _) }
87+
equiv_rw G.left_moves_neg at i <|> equiv_rw G.right_moves_neg at i,
88+
simp only [move_left_left_moves_neg_symm, move_right_right_moves_neg_symm],
89+
exact impartial_neg _ }
10090
end
101-
using_well_founded {dec_tac := pgame_wf_tac}
91+
using_well_founded { dec_tac := pgame_wf_tac }
10292

103-
lemma impartial_winner_cases {G : pgame} (hG : G.impartial) : G.first_loses ∨ G.first_wins :=
93+
lemma winner_cases (G : pgame) [G.impartial] : G.first_loses ∨ G.first_wins :=
10494
begin
10595
rcases G.winner_cases with hl | hr | hp | hn,
10696
{ cases hl with hpos hnonneg,
10797
rw ←not_lt at hnonneg,
108-
have hneg := lt_of_lt_of_equiv hpos (impartial_neg_equiv_self hG),
98+
have hneg := lt_of_lt_of_equiv hpos (neg_equiv_self G),
10999
rw [lt_iff_neg_gt, neg_neg, neg_zero] at hneg,
110100
contradiction },
111101
{ cases hr with hnonpos hneg,
112102
rw ←not_lt at hnonpos,
113-
have hpos := lt_of_equiv_of_lt (impartial_neg_equiv_self hG).symm hneg,
103+
have hpos := lt_of_equiv_of_lt (neg_equiv_self G).symm hneg,
114104
rw [lt_iff_neg_gt, neg_neg, neg_zero] at hpos,
115105
contradiction },
116106
{ left, assumption },
117107
{ right, assumption }
118108
end
119109

120-
lemma impartial_not_first_wins {G : pgame} (hG : G.impartial) : ¬G.first_wins ↔ G.first_loses :=
121-
by cases impartial_winner_cases hG; finish using [not_first_loses_of_first_wins]
110+
lemma not_first_wins (G : pgame) [G.impartial] : ¬G.first_wins ↔ G.first_loses :=
111+
by cases winner_cases G; finish using [not_first_loses_of_first_wins]
122112

123-
lemma impartial_not_first_loses {G : pgame} (hG : G.impartial) : ¬G.first_loses ↔ G.first_wins :=
124-
iff.symm $ iff_not_comm.1 $ iff.symm $ impartial_not_first_wins hG
113+
lemma not_first_loses (G : pgame) [G.impartial] : ¬G.first_loses ↔ G.first_wins :=
114+
iff.symm $ iff_not_comm.1 $ iff.symm $ not_first_wins G
125115

126-
lemma impartial_add_self {G : pgame} (hG : G.impartial) : (G + G).first_loses :=
127-
first_loses_is_zero.2 $ equiv_trans (add_congr (impartial_neg_equiv_self hG) G.equiv_refl)
116+
lemma add_self (G : pgame) [G.impartial] : (G + G).first_loses :=
117+
first_loses_is_zero.2 $ equiv_trans (add_congr (neg_equiv_self G) G.equiv_refl)
128118
add_left_neg_equiv
129119

130-
lemma equiv_iff_sum_first_loses {G H : pgame} (hG : G.impartial) (hH : H.impartial) :
120+
lemma equiv_iff_sum_first_loses (G H : pgame) [G.impartial] [H.impartial] :
131121
G ≈ H ↔ (G + H).first_loses :=
132122
begin
133123
split,
134124
{ intro heq,
135-
exact first_loses_of_equiv (add_congr (equiv_refl _) heq) (impartial_add_self hG) },
125+
exact first_loses_of_equiv (add_congr (equiv_refl _) heq) (add_self G) },
136126
{ intro hGHp,
137127
split,
138128
{ rw le_iff_sub_nonneg,
139129
exact le_trans hGHp.2
140130
(le_trans add_comm_le $ le_of_le_of_equiv (le_refl _) $ add_congr (equiv_refl _)
141-
(impartial_neg_equiv_self hG)) },
131+
(neg_equiv_self G)) },
142132
{ rw le_iff_sub_nonneg,
143133
exact le_trans hGHp.2
144-
(le_of_le_of_equiv (le_refl _) $ add_congr (equiv_refl _) (impartial_neg_equiv_self hH)) } }
134+
(le_of_le_of_equiv (le_refl _) $ add_congr (equiv_refl _) (neg_equiv_self H)) } }
145135
end
146136

147-
lemma impartial_first_loses_symm {G : pgame} (hG : G.impartial) : G.first_loses ↔ G ≤ 0 :=
148-
begin
149-
use and.left,
150-
{ intro hneg,
151-
use hneg,
152-
exact zero_le_iff_neg_le_zero.2 (le_of_equiv_of_le (impartial_neg_equiv_self hG).symm hneg) }
153-
end
137+
lemma le_zero_iff {G : pgame} [G.impartial] : G ≤ 00 ≤ G :=
138+
by rw [le_zero_iff_zero_le_neg, le_congr (equiv_refl 0) (neg_equiv_self G)]
154139

155-
lemma impartial_first_wins_symm {G : pgame} (hG : G.impartial) : G.first_wins ↔ G < 0 :=
156-
begin
157-
use and.right,
158-
{ intro hneg,
159-
split,
160-
rw lt_iff_neg_gt,
161-
rw neg_zero,
162-
exact lt_of_equiv_of_lt (impartial_neg_equiv_self hG).symm hneg,
163-
exact hneg }
164-
end
140+
lemma lt_zero_iff {G : pgame} [G.impartial] : G < 00 < G :=
141+
by rw [lt_iff_neg_gt, neg_zero, lt_congr (equiv_refl 0) (neg_equiv_self G)]
165142

166-
lemma impartial_first_loses_symm' {G : pgame} (hG : G.impartial) : G.first_loses ↔ 0 ≤ G :=
167-
begin
168-
use and.right,
169-
{ intro hpos,
170-
use le_zero_iff_zero_le_neg.2 (le_of_le_of_equiv hpos $ impartial_neg_equiv_self hG),
171-
exact hpos }
172-
end
143+
lemma first_loses_symm (G : pgame) [G.impartial] : G.first_loses ↔ G ≤ 0 :=
144+
⟨and.left, λ h, ⟨h, le_zero_iff.1 h⟩⟩
173145

174-
lemma impartial_first_wins_symm' {G : pgame} (hG : G.impartial) : G.first_wins ↔ 0 < G :=
175-
begin
176-
use and.left,
177-
{ intro hpos,
178-
use hpos,
179-
rw lt_iff_neg_gt,
180-
rw neg_zero,
181-
exact lt_of_lt_of_equiv hpos (impartial_neg_equiv_self hG) }
182-
end
146+
lemma first_wins_symm (G : pgame) [G.impartial] : G.first_wins ↔ G < 0 :=
147+
⟨and.right, λ h, ⟨lt_zero_iff.1 h, h⟩⟩
148+
149+
lemma first_loses_symm' (G : pgame) [G.impartial] : G.first_loses ↔ 0 ≤ G :=
150+
⟨and.right, λ h, ⟨le_zero_iff.2 h, h⟩⟩
151+
152+
lemma first_wins_symm' (G : pgame) [G.impartial] : G.first_wins ↔ 0 < G :=
153+
⟨and.left, λ h, ⟨h, lt_zero_iff.2 h⟩⟩
183154

184-
lemma no_good_left_moves_iff_first_loses {G : pgame} (hG : G.impartial) :
155+
lemma no_good_left_moves_iff_first_loses (G : pgame) [G.impartial] :
185156
(∀ (i : G.left_moves), (G.move_left i).first_wins) ↔ G.first_loses :=
186157
begin
187158
split,
188159
{ intro hbad,
189-
rw [impartial_first_loses_symm hG, le_def_lt],
160+
rw [first_loses_symm G, le_def_lt],
190161
split,
191162
{ intro i,
192163
specialize hbad i,
193164
exact hbad.2 },
194165
{ intro j,
195166
exact pempty.elim j } },
196167
{ intros hp i,
197-
rw impartial_first_wins_symm (impartial_move_left_impartial hG _),
198-
exact (le_def_lt.1 $ (impartial_first_loses_symm hG).1 hp).1 i }
168+
rw first_wins_symm,
169+
exact (le_def_lt.1 $ (first_loses_symm G).1 hp).1 i }
199170
end
200171

201-
lemma no_good_right_moves_iff_first_loses {G : pgame} (hG : G.impartial) :
172+
lemma no_good_right_moves_iff_first_loses (G : pgame) [G.impartial] :
202173
(∀ (j : G.right_moves), (G.move_right j).first_wins) ↔ G.first_loses :=
203174
begin
204-
split,
205-
{ intro hbad,
206-
rw [impartial_first_loses_symm' hG, le_def_lt],
207-
split,
208-
{ intro i,
209-
exact pempty.elim i },
210-
{ intro j,
211-
specialize hbad j,
212-
exact hbad.1 } },
213-
{ intros hp j,
214-
rw impartial_first_wins_symm' (impartial_move_right_impartial hG _),
215-
exact ((le_def_lt.1 $ (impartial_first_loses_symm' hG).1 hp).2 j) }
175+
rw [first_loses_of_equiv_iff (neg_equiv_self G), ←no_good_left_moves_iff_first_loses],
176+
refine ⟨λ h i, _, λ h i, _⟩,
177+
{ simpa [first_wins_of_equiv_iff (neg_equiv_self ((-G).move_left i))]
178+
using h (left_moves_neg _ i) },
179+
{ simpa [first_wins_of_equiv_iff (neg_equiv_self (G.move_right i))]
180+
using h ((left_moves_neg _).symm i) }
216181
end
217182

218-
lemma good_left_move_iff_first_wins {G : pgame} (hG : G.impartial) :
183+
lemma good_left_move_iff_first_wins (G : pgame) [G.impartial] :
219184
(∃ (i : G.left_moves), (G.move_left i).first_loses) ↔ G.first_wins :=
220185
begin
221-
split,
222-
{ rintro ⟨ i, hi ⟩,
223-
exact (impartial_first_wins_symm' hG).2 (lt_def_le.2 $ or.inl ⟨ i, hi.2 ⟩) },
224-
{ intro hn,
225-
rw [impartial_first_wins_symm' hG, lt_def_le] at hn,
226-
rcases hn with ⟨ i, hi ⟩ | ⟨ j, _ ⟩,
227-
{ exact ⟨ i, (impartial_first_loses_symm' $ impartial_move_left_impartial hG _).2 hi ⟩ },
228-
{ exact pempty.elim j } }
186+
refine ⟨λ ⟨i, hi⟩, (first_wins_symm' G).2 (lt_def_le.2 $ or.inl ⟨i, hi.2⟩), λ hn, _⟩,
187+
rw [first_wins_symm' G, lt_def_le] at hn,
188+
rcases hn with ⟨i, hi⟩ | ⟨j, _⟩,
189+
{ exact ⟨i, (first_loses_symm' _).2 hi⟩ },
190+
{ exact pempty.elim j }
229191
end
230192

231-
lemma good_right_move_iff_first_wins {G : pgame} (hG : G.impartial) :
193+
lemma good_right_move_iff_first_wins (G : pgame) [G.impartial] :
232194
(∃ j : G.right_moves, (G.move_right j).first_loses) ↔ G.first_wins :=
233195
begin
234-
split,
235-
{ rintro ⟨ j, hj ⟩,
236-
exact (impartial_first_wins_symm hG).2 (lt_def_le.2 $ or.inr ⟨ j, hj.1 ⟩) },
237-
{ intro hn,
238-
rw [impartial_first_wins_symm hG, lt_def_le] at hn,
239-
rcases hn with ⟨ i, _ ⟩ | ⟨ j, hj ⟩,
240-
{ exact pempty.elim i },
241-
{ exact ⟨ j, (impartial_first_loses_symm $ impartial_move_right_impartial hG _).2 hj ⟩ } }
196+
refine ⟨λ ⟨j, hj⟩, (first_wins_symm G).2 (lt_def_le.2 $ or.inr ⟨j, hj.1⟩), λ hn, _⟩,
197+
rw [first_wins_symm G, lt_def_le] at hn,
198+
rcases hn with ⟨i, _⟩ | ⟨j, hj⟩,
199+
{ exact pempty.elim i },
200+
{ exact ⟨j, (first_loses_symm _).2 hj⟩ }
242201
end
243202

203+
end impartial
244204
end pgame

0 commit comments

Comments
 (0)