forked from CakeML/cakeml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cfHeapsBaseLib.sml
419 lines (355 loc) · 12.4 KB
/
cfHeapsBaseLib.sml
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
(*
Implements CF tactics for CF-style separation logic
*)
structure cfHeapsBaseLib :> cfHeapsBaseLib =
struct
open preamble
open set_sepTheory helperLib ConseqConv
open evarsConseqConvLib
open cfHeapsBaseTheory cfTacticsBaseLib
open cfHeapsBaseSyntax
infix 3 THEN_DCC
infix 3 ORELSE_DCC
(** Prove an "easy" goal about sets, involving UNION, DISJOINT,... Useful after
unfolding the definitions of heap predicates. *)
val SPLIT_TAC = fs [SPLIT_def,SPLIT3_def,SUBSET_DEF,DISJOINT_DEF,DELETE_DEF,
IN_INSERT,UNION_DEF,SEP_EQ_def,EXTENSION,NOT_IN_EMPTY,
IN_DEF,IN_UNION,IN_INTER,IN_DIFF]
\\ metis_tac []
(** Normalization of STAR *)
val rew_heap_thms =
[AC STAR_COMM STAR_ASSOC, SEP_CLAUSES, STARPOST_emp,
SEP_IMPPOST_def, STARPOST_def, cond_eq_def]
val rew_heap = full_simp_tac bool_ss rew_heap_thms
val rew_heap_AC = full_simp_tac bool_ss [AC STAR_COMM STAR_ASSOC]
val SEP_CLAUSES = LIST_CONJ [SEP_CLAUSES, STARPOST_def, cond_eq_def]
val heap_clean_conv =
SIMP_CONV bool_ss [SEP_CLAUSES] THENC
DEPTH_CONV (REWR_CONV SEP_F_to_cond)
val SEP_IMPPOST_VARIANTS = LIST_CONJ
[SEP_IMPPOST_def, SEP_IMPPOSTv_def, SEP_IMPPOSTe_def,
SEP_IMPPOSTf_def, SEP_IMPPOSTd_def, SEP_IMPPOSTv_inv_def,
SEP_IMPPOSTe_inv_def]
(*------------------------------------------------------------------*)
(** Auxiliary functions *)
fun SEP_IMP_conv convl convr t =
let val (l, r) = dest_sep_imp t
val rew_t = MATCH_MP (MATCH_MP SEP_IMP_rew (convl l)) (convr r)
in UNCHANGED_CONV (REWR_CONV rew_t) t
end
fun rearrange_star_conv tm rest =
let val rearranged = list_mk_star (rest @ [tm]) ``:hprop`` in
fn t => ml_translatorLib.auto_prove "rearrange_star_conv"
(mk_eq (t, rearranged), rew_heap_AC)
end
(** hpullable *)
val hpullable_error = ERR "hpullable" "need to first call xpull"
(* [hpullable_rec H] raises an error if the heap predicate [H]
contains existentials or non-empty pure facts. *)
fun hpullable_rec tm =
let val hs = list_dest dest_star tm in
app (fn h =>
if is_cond h orelse is_sep_exists h then
raise hpullable_error
else ()) hs
end
(* [hpullable t] applies to a term of the form [H ==>> H'], and raises
an error if [H] contains extractible quantifiers or facts *)
fun hpullable tm =
let val (l, _) = dest_sep_imp tm
in hpullable_rec l end
(** hpull *)
fun hpull_one_conseq_conv_core t =
let
val (l, r) = dest_sep_imp t
val ls = list_dest dest_star l
fun rearrange_conv tm =
let val rest = filter (not o aconv tm) ls in
SEP_IMP_conv (rearrange_star_conv tm rest) REFL
end
fun pull tm =
if is_cond tm then
SOME (
THEN_CONSEQ_CONV
(rearrange_conv tm)
(CONSEQ_TOP_REWRITE_CONV ([], [hpull_prop, hpull_prop_single], [])
CONSEQ_CONV_STRENGTHEN_direction)
)
else if is_sep_exists tm then
SOME (
EVERY_CONSEQ_CONV [
rearrange_conv tm,
CONSEQ_TOP_REWRITE_CONV ([], [hpull_exists_single], [])
CONSEQ_CONV_STRENGTHEN_direction,
REDEPTH_STRENGTHEN_CONSEQ_CONV (REDEPTH_CONV BETA_CONV)
]
)
else
NONE
in
case find_map pull ls of
NONE => raise UNCHANGED
| SOME cc => cc t
end
val hpull_setup_conv =
(* cleanup the left heap a bit (remove ``emp``, pull SEP_EXISTS,...) *)
SEP_IMP_conv (QCONV heap_clean_conv) REFL
val hpull_one_conseq_conv =
STRENGTHEN_CONSEQ_CONV hpull_setup_conv THEN_DCC
STRENGTHEN_CONSEQ_CONV hpull_one_conseq_conv_core
val hpull_conseq_conv =
STRENGTHEN_CONSEQ_CONV hpull_setup_conv THEN_DCC
REDEPTH_CONSEQ_CONV (STRENGTHEN_CONSEQ_CONV hpull_one_conseq_conv_core)
val hpull_one = CONSEQ_CONV_TAC hpull_one_conseq_conv
val hpull = CONSEQ_CONV_TAC hpull_conseq_conv
(* test goals:
g `(A * cond P * (SEP_EXISTS x. G x) * cond Q :hprop) ==>> Z`;
e (CONSEQ_CONV_TAC hpull_one_conseq_conv \\ strip_tac);
e (CONSEQ_CONV_TAC hpull_one_conseq_conv \\ strip_tac);
e (CONSEQ_CONV_TAC hpull_one_conseq_conv \\ strip_tac);
g `(A * cond P * (SEP_EXISTS x. G x) * cond Q :hprop) ==>> Z`;
e (CONSEQ_CONV_TAC hpull_conseq_conv);
g `(A * emp * cond P * (SEP_EXISTS x. emp * G x) * cond Q :hprop) ==>> Z`;
e (CONSEQ_CONV_TAC hpull_conseq_conv);
g `(A * emp) ==>> Z`;
e (CONSEQ_CONV_TAC hpull_conseq_conv);
*)
(** hsimpl_cancel *)
fun hsimpl_cancel_one_conseq_conv_core t =
let
val (l, r) = dest_sep_imp t
val ls = list_dest dest_star l
val rs = list_dest dest_star r
val is = op_intersect aconv ls rs
fun rearrange_conv tm1 tm2 =
let
val ls' = filter (not o aconv tm1) ls
val rs' = filter (not o aconv tm2) rs
val convl = rearrange_star_conv tm1 ls'
val convr = rearrange_star_conv tm2 rs'
in SEP_IMP_conv convl convr
end
fun cell_loc tm =
SOME (fst (dest_cell tm)) handle _ =>
SOME (fst (dest_REF tm)) handle _ =>
SOME (fst (dest_ARRAY tm)) handle _ =>
SOME (fst (dest_W8ARRAY tm)) handle _ =>
SOME (#3 (dest_IO tm)) handle _ =>
NONE
fun same_cell_kind tm1 tm2 =
(is_cell tm1 andalso is_cell tm2) orelse
(is_REF tm1 andalso is_REF tm2) orelse
(is_ARRAY tm1 andalso is_ARRAY tm2) orelse
(is_W8ARRAY tm1 andalso is_W8ARRAY tm2) orelse
(is_IO tm1 andalso is_IO tm2)
fun find_matching_cells () =
find_map (fn tm1 =>
Option.mapPartial (fn loc =>
find_map (fn tm2 =>
Option.mapPartial (fn loc' =>
if loc ~~ loc' andalso same_cell_kind tm1 tm2 then
SOME (tm1, tm2)
else NONE
) (cell_loc tm2)
) rs
) (cell_loc tm1)
) ls
val frame_thms = [
SEP_IMP_FRAME,
SEP_IMP_frame_single_l,
SEP_IMP_frame_single_r
]
val frame_cell_thms = [
SEP_IMP_cell_frame,
SEP_IMP_cell_frame_single_l,
SEP_IMP_cell_frame_single_r,
SEP_IMP_cell_frame_single,
SEP_IMP_REF_frame,
SEP_IMP_REF_frame_single_l,
SEP_IMP_REF_frame_single_r,
SEP_IMP_REF_frame_single,
SEP_IMP_ARRAY_frame,
SEP_IMP_ARRAY_frame_single_l,
SEP_IMP_ARRAY_frame_single_r,
SEP_IMP_ARRAY_frame_single,
SEP_IMP_W8ARRAY_frame,
SEP_IMP_W8ARRAY_frame_single_l,
SEP_IMP_W8ARRAY_frame_single_r,
SEP_IMP_W8ARRAY_frame_single,
SEP_IMP_IO_frame,
SEP_IMP_IO_frame_single_l,
SEP_IMP_IO_frame_single_r,
SEP_IMP_IO_frame_single
]
in
case is of
tm :: _ =>
THEN_CONSEQ_CONV
(rearrange_conv tm tm)
(CONSEQ_TOP_REWRITE_CONV ([], frame_thms, [])
CONSEQ_CONV_STRENGTHEN_direction) t
| [] =>
case find_matching_cells () of
SOME (tm1, tm2) =>
THEN_CONSEQ_CONV
(rearrange_conv tm1 tm2)
(CONSEQ_TOP_REWRITE_CONV ([], frame_cell_thms, [])
CONSEQ_CONV_STRENGTHEN_direction) t
| NONE => raise UNCHANGED
end
val hsimpl_cancel_one_conseq_conv =
STRENGTHEN_CONSEQ_CONV hsimpl_cancel_one_conseq_conv_core
val hsimpl_cancel_conseq_conv =
REDEPTH_CONSEQ_CONV hsimpl_cancel_one_conseq_conv
val hsimpl_cancel_one = CONSEQ_CONV_TAC hsimpl_cancel_one_conseq_conv
val hsimpl_cancel = CONSEQ_CONV_TAC hsimpl_cancel_conseq_conv
(* test goal:
g `(v = v' ==>
(A:hprop * B * C * l ~~> v * l' ~~> w * D) ==>> (l' ~~> z * B * Z * l ~~> v' * Y * D * A))`;
e strip_tac;
e hsimpl_cancel_one;
e hsimpl_cancel_one;
e hsimpl_cancel_one;
e (hsimpl_cancel_one \\ strip_tac THEN1 (fs []));
e hsimpl_cancel_one;
(* or alternatively *)
e hsimpl_cancel;
*)
(** hpullr *)
fun hpullr_conseq_conv_core t =
let
val (l, r) = dest_sep_imp t
val rs = list_dest dest_star r
fun rearrange_conv tm =
let val rest = filter (not o aconv tm) rs in
SEP_IMP_conv REFL (rearrange_star_conv tm rest)
end
fun simpl tm =
if is_cond tm then
SOME (
EVERY_CONSEQ_CONV [
rearrange_conv tm,
CONSEQ_TOP_REWRITE_CONV ([], [hsimpl_prop, hsimpl_prop_single], [])
CONSEQ_CONV_STRENGTHEN_direction
]
)
else if is_sep_exists tm then
SOME (
EVERY_CONSEQ_CONV [
rearrange_conv tm,
CONSEQ_TOP_REWRITE_CONV ([], [hsimpl_exists_single], [])
CONSEQ_CONV_STRENGTHEN_direction,
REDEPTH_STRENGTHEN_CONSEQ_CONV (REDEPTH_CONV BETA_CONV)
]
)
else
NONE
in
case find_map simpl rs of
NONE => raise UNCHANGED
| SOME cc => cc t
end
val hpullr_setup_conv =
SEP_IMP_conv REFL (QCONV heap_clean_conv)
val hpullr_one_conseq_conv =
STRENGTHEN_CONSEQ_CONV hpullr_setup_conv THEN_DCC
STRENGTHEN_CONSEQ_CONV hpullr_conseq_conv_core
val hpullr_conseq_conv =
STRENGTHEN_CONSEQ_CONV hpullr_setup_conv THEN_DCC
REDEPTH_CONSEQ_CONV (STRENGTHEN_CONSEQ_CONV hpullr_conseq_conv_core)
val hpullr_one = CONSEQ_CONV_TAC hpullr_one_conseq_conv
val hpullr = CONSEQ_CONV_TAC hpullr_conseq_conv
(* test goal:
g `Z ==>> (A * cond P * (SEP_EXISTS x. G x) * cond Q :hprop)`;
e hpullr_one;
e (DEPTH_CONSEQ_CONV_TAC hpullr_one_conseq_conv);
e (DEPTH_CONSEQ_CONV_TAC hpullr_one_conseq_conv);
(* alternatively *)
e hpullr;
*)
(** hcancel: hsimpl_cancel + hpullr *)
val SCC = STRENGTHEN_CONSEQ_CONV
val hcancel_setup_conv =
SEP_IMP_conv
(QCONV heap_clean_conv)
(QCONV heap_clean_conv)
val hcancel_conseq_conv =
EXT_DEPTH_CONSEQ_CONV
(CONSEQ_CONV_get_context_congruences CONSEQ_CONV_NO_CONTEXT)
CONSEQ_CONV_default_cache_opt NONE
true (* redepth *)
[(true, NONE, K (SCC (REWR_CONV SEP_IMPPOST_unfold))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTv_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTe_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTf_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTd_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTv_inv_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTe_inv_def))),
(true, NONE, K (SCC hcancel_setup_conv)),
(true, NONE, K hsimpl_cancel_conseq_conv),
(true, NONE, K hpullr_conseq_conv),
(false, NONE, K (SCC (TRY_CONV LIST_FORALL_SIMP_CONV))),
(false, NONE, K (SCC (SIMP_CONV bool_ss [hsimpl_gc, SEP_IMP_REFL])))
]
[]
val hcancel =
CONSEQ_CONV_TAC hcancel_conseq_conv
(** hsimpl *)
val hsimpl_conseq_conv =
EXT_DEPTH_CONSEQ_CONV
(CONSEQ_CONV_get_context_congruences CONSEQ_CONV_NO_CONTEXT)
CONSEQ_CONV_default_cache_opt NONE
true (* redepth *)
[(true, NONE, K (SCC (REWR_CONV SEP_IMPPOST_unfold))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTv_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTe_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTf_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTd_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTv_inv_def))),
(true, NONE, K (SCC (REWR_CONV SEP_IMPPOSTe_inv_def))),
(true, NONE, K (SCC hcancel_setup_conv)),
(true, NONE, K hpull_conseq_conv),
(true, NONE, K hsimpl_cancel_conseq_conv),
(true, NONE, K hpullr_conseq_conv),
(false, NONE, K (SCC (TRY_CONV LIST_FORALL_SIMP_CONV))),
(false, NONE, K (SCC (SIMP_CONV bool_ss [hsimpl_gc, SEP_IMP_REFL])))
]
[]
val hsimpl =
CONSEQ_CONV_TAC hsimpl_conseq_conv
(* test goal:
g `(A:hprop * B * C * l ~~> v * l' ~~> u * D) ==>> (B * Z * l ~~> v' * l' ~~> u' * Y * cond Q * D * A)`;
e (CONSEQ_CONV_TAC hsimpl_conseq_conv);
e hsimpl;
g `emp ==>> emp`;
e hsimpl
*)
(** sep_imp_instantiate: instantiate existentially quantified
variables after subterms of the form ``H1 ==>> H2`` where one of
{H1, H2} is existentially quantified, and not the other.
*)
infix then_ecc
fun sep_imp_instantiate {term, evars} = let
val ts = strip_conj term
fun find_inst t = let
val (H1, H2) = dest_sep_imp t in
if tmem H1 evars andalso not (tmem H2 evars) then
{instantiation = [H1 |-> H2], new_evars = []}
else if tmem H2 evars andalso not (tmem H1 evars) then
{instantiation = [H2 |-> H1], new_evars = []}
else fail ()
end
fun find_inst' t = SOME (find_inst t) handle HOL_ERR _ => NONE
in
case find_map find_inst' ts of
SOME inst => inst
| NONE => fail ()
end
val hinst_ecc =
repeat_ecc (instantiate_ecc sep_imp_instantiate) then_ecc
lift_conseq_conv_ecc (SIMP_CONV bool_ss [hsimpl_gc, SEP_IMP_REFL])
val hinst =
CONSEQ_CONV_TAC
(STRENGTHEN_CONSEQ_CONV
(ecc_conseq_conv hinst_ecc))
end