-
Notifications
You must be signed in to change notification settings - Fork 2
/
Metatheory_Fresh.v
309 lines (250 loc) · 8.68 KB
/
Metatheory_Fresh.v
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
309
(***************************************************************************
* Tactics to Automate Reasoning about Freshness *
* Brian Aydemir & Arthur Charguéraud, July 2007, Coq v8.1 *
***************************************************************************)
Set Implicit Arguments.
Require Import Lib_Tactic List Metatheory_Var.
Ltac fresh_simpl_to_notin_in_context :=
repeat (match goal with H: fresh _ _ _ |- _ =>
progress (simpl in H; destruct H) end).
(* ********************************************************************** *)
(** ** Tactics for notin *)
(** For efficiency, we avoid rewrites by splitting equivalence. *)
Lemma notin_singleton_r : forall x y,
x \notin {{y}} -> x <> y.
intros. rewrite* <- notin_singleton.
Qed.
Lemma notin_singleton_l : forall x y,
x <> y -> x \notin {{y}}.
intros. rewrite* notin_singleton.
Qed.
Lemma notin_singleton_swap : forall x y,
x \notin {{y}} -> y \notin {{x}}.
intros. apply notin_singleton_l.
apply sym_not_eq. apply* notin_singleton_r.
Qed.
Lemma notin_union_r : forall x E F,
x \notin (E \u F) -> (x \notin E) /\ (x \notin F).
intros. rewrite* <- notin_union.
Qed.
Lemma notin_union_l : forall x E F,
x \notin E -> x \notin F -> x \notin (E \u F).
intros. rewrite* notin_union.
Qed.
(** Tactics to deal with notin. It interacts with union
singleton and empty, but not inclusion. *)
Ltac notin_solve_from x E H :=
match type of H with x \notin ?L =>
match L with context[E] =>
match L with
| E => exact H
| ?F \u ?G =>
let P := constr:(@notin_union_r x F G H) in
let PF := eval simpl in (proj1 P) in
let PG := eval simpl in (proj2 P) in
solve [ notin_solve_from x E PF
| notin_solve_from x E PG ]
end
end
end.
Ltac notin_solve_from_context x E :=
match goal with H: x \notin _ |- _ =>
notin_solve_from x E H end.
Ltac notin_solve_one :=
match goal with
| |- _ \notin {} =>
apply notin_empty
| |- ?x \notin {{?y}} => (* by x <> y or y <> x *)
apply notin_singleton_l; solve
[ assumption | apply sym_not_eq; assumption ]
| |- ?x \notin {{?y}} => (* by y \notin {{x}} *)
apply notin_singleton_swap; notin_solve_from_context y ({{x}})
| |- ?x \notin ?E => (* default search *)
notin_solve_from_context x E
end.
Ltac notin_simpl :=
try match goal with |- _ \notin (_ \u _) =>
apply notin_union_l; notin_simpl end.
Ltac notin_simpl_hyps := (* forward-chaining *)
try match goal with
| H: _ \notin {} |- _ =>
clear H; notin_simpl_hyps
| H: ?x \notin {{?y}} |- _ =>
puts (@notin_singleton_r x y H);
clear H; notin_simpl_hyps
| H: ?x \notin (?E \u ?F) |- _ =>
let H1 := fresh "Fr" in let H2 := fresh "Fr" in
destruct (@notin_union_r x E F H) as [H1 H2];
clear H; notin_simpl_hyps
end.
Ltac notin_simpls :=
notin_simpl_hyps; notin_simpl.
Ltac notin_solve :=
fresh_simpl_to_notin_in_context;
notin_simpl; notin_solve_one.
Ltac notin_contradiction :=
match goal with H: ?x \notin ?E |- _ =>
match E with context[x] =>
let K := fresh in assert (K : x \notin {{x}});
[ notin_solve_one
| contradictions; apply (notin_same K) ]
end
end.
Ltac notin_neq_solve :=
apply notin_singleton_r; notin_solve.
Ltac fold_notin :=
repeat match goal with
| H: context [?x \in ?E -> False] |- _ =>
fold (not (x \in E)) in H
| |- context [?x \in ?E -> False] =>
fold (not (x \in E)) end.
(* ********************************************************************** *)
(** Demo for notin *)
Lemma test_notin_solve_1 : forall x E F G,
x \notin E \u F -> x \notin G -> x \notin (E \u G).
intros. notin_solve.
Qed.
Lemma test_notin_solve_2 : forall x y E F G,
x \notin E \u {{y}} \u F -> x \notin G ->
x \notin {{y}} /\ y \notin {{x}}.
intros. split. notin_solve. notin_solve.
Qed.
Lemma test_notin_solve_3 : forall x y,
x <> y -> x \notin {{y}} /\ y \notin {{x}}.
intros. split. notin_solve. notin_solve.
Qed.
Lemma test_notin_contradiction : forall x y E F G,
x \notin (E \u {{x}} \u F) -> y \notin G.
intros. notin_contradiction.
Qed.
Lemma test_neq_solve : forall x y E F,
x \notin (E \u {{y}} \u F) -> y \notin E ->
y <> x /\ x <> y.
intros. split. notin_neq_solve. notin_neq_solve.
Qed.
(***************************************************************************)
(** Automation: hints to solve "notin" subgoals automatically. *)
Hint Extern 1 (_ \notin _) => notin_solve : core.
Hint Extern 1 (_ \in _ -> False) => fold_notin : core.
Hint Extern 1 (_ <> _ :> var) => notin_neq_solve : core.
Hint Extern 1 (_ <> _ :> S.elt) => notin_neq_solve : core.
(* ********************************************************************** *)
(** ** Tactics for fresh *)
Hint Extern 1 (fresh _ _ _) => simpl : core.
Lemma fresh_union_r : forall xs L1 L2 n,
fresh (L1 \u L2) n xs -> fresh L1 n xs /\ fresh L2 n xs.
Proof.
induction xs; simpl; intros; destruct n;
try solve [ contradictions* ]. auto.
destruct H. splits~.
forward* (@IHxs (L1 \u {{a}}) L2 n).
rewrite union_comm.
rewrite union_comm_assoc.
rewrite* union_assoc.
forward* (@IHxs L1 (L2 \u {{a}}) n).
rewrite* union_assoc.
Qed.
Lemma fresh_union_l : forall xs L1 L2 n,
fresh L1 n xs -> fresh L2 n xs -> fresh (L1 \u L2) n xs.
Proof.
induction xs; simpl; intros; destruct n;
try solve [ contradictions* ]. auto.
destruct H. destruct H0. split2~.
forward~ (@IHxs (L1 \u {{a}}) (L2 \u {{a}}) n).
intros K.
rewrite <- (union_same {{a}}).
rewrite union_assoc.
rewrite <- (@union_assoc L1).
rewrite (@union_comm L2).
rewrite (@union_assoc L1).
rewrite* <- union_assoc.
Qed.
Lemma fresh_empty : forall L n xs,
fresh L n xs -> fresh {} n xs.
Proof.
intros. rewrite <- (@union_empty_r L) in H.
destruct* (fresh_union_r _ _ _ _ H).
Qed.
Lemma fresh_length : forall xs L n,
fresh L n xs -> n = length xs.
Proof.
induction xs; simpl; intros L n Fr; destruct n;
try solve [contradictions*]. auto.
rewrite* <- (@IHxs (L \u {{a}}) n).
Qed.
Lemma fresh_resize : forall n xs L,
fresh L n xs -> fresh L (length xs) xs.
Proof.
introv Fr. rewrite* <- (fresh_length _ _ _ Fr).
Qed.
Ltac fresh_solve_from xs n E H :=
match type of H with fresh ?L _ _ =>
match L with context[E] =>
match L with
| E => exact H
| ?F \u ?G =>
let P := constr:(@fresh_union_r xs F G n H) in
let PF := eval simpl in (proj1 P) in
let PG := eval simpl in (proj2 P) in
solve [ fresh_solve_from xs n E PF
| fresh_solve_from xs n E PG ]
end
end
end.
Ltac fresh_solve_from_context xs n E :=
match goal with H: fresh _ n xs |- _ =>
fresh_solve_from xs n E H end.
Ltac fresh_solve_one :=
assumption ||
match goal with
| |- fresh {} ?n ?xs =>
match goal with H: fresh ?L n xs |- _ =>
apply (@fresh_empty L n xs H) end
(* | H: fresh _ ?n ?xs |- fresh ?E ?n ?xs =>
fresh_solve_from xs n E H *)
| |- fresh _ (length ?xs) ?xs =>
match goal with H: fresh _ ?n xs |- _ =>
progress (apply (@fresh_resize n)); fresh_solve_one end
end.
Ltac fresh_simpl :=
try match goal with |- fresh (_ \u _) _ _ =>
apply fresh_union_l; fresh_simpl end.
Ltac fresh_split :=
match goal with
| H: fresh (?L1 \u ?L2) ?n ?xs |- fresh _ _ ?xs =>
destruct (fresh_union_r xs L1 L2 n H); clear H; fresh_split
| _ => try fresh_simpl
end.
Ltac fresh_simpl_to_notin_in_goal :=
simpl; splits.
Ltac fresh_simpl_to_notin_solve :=
fresh_simpl_to_notin_in_context;
fresh_simpl_to_notin_in_goal;
notin_solve.
Ltac fresh_solve :=
(fresh_split; fresh_solve_one) || (fresh_simpl; fresh_simpl_to_notin_solve).
(* ********************************************************************** *)
(** Demo for notin *)
Lemma test_fresh_solve_1 : forall xs L1 L2 n,
fresh (L1 \u L2) n xs -> fresh L1 n xs.
Proof.
intros. fresh_solve.
Qed.
Lemma test_fresh_solve_2 : forall xs L1 L2 n,
fresh (L1 \u L2) n xs -> fresh L2 n xs.
Proof.
intros. fresh_solve.
Qed.
Lemma test_fresh_solve_3 : forall xs L1 L2 n,
fresh (L1 \u L2) n xs -> fresh {} n xs.
Proof.
intros. fresh_solve.
Qed.
Lemma test_fresh_solve_4 : forall xs L1 L2 n,
fresh (L1 \u L2) n xs -> fresh L1 (length xs) xs.
Proof.
intros. fresh_solve.
Qed.
(***************************************************************************)
(** Automation: hints to solve "fresh" subgoals automatically. *)
Hint Extern 1 (fresh _ _ _) => fresh_solve : core.