forked from jrh13/hol-light
-
Notifications
You must be signed in to change notification settings - Fork 0
/
simp.ml
561 lines (467 loc) · 24.1 KB
/
simp.ml
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
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
(* ========================================================================= *)
(* Simplification and rewriting. *)
(* *)
(* John Harrison, University of Cambridge Computer Laboratory *)
(* *)
(* (c) Copyright, University of Cambridge 1998 *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* ========================================================================= *)
needs "itab.ml";;
(* ------------------------------------------------------------------------- *)
(* Generalized conversion (conversion plus a priority). *)
(* ------------------------------------------------------------------------- *)
type gconv = int * conv;;
(* ------------------------------------------------------------------------- *)
(* Primitive rewriting conversions: unconditional and conditional equations. *)
(* ------------------------------------------------------------------------- *)
let REWR_CONV = PART_MATCH lhs;;
let IMP_REWR_CONV = PART_MATCH (lhs o snd o dest_imp);;
(* ------------------------------------------------------------------------- *)
(* Versions with ordered rewriting. We must have l' > r' for the rewrite *)
(* |- l = r (or |- c ==> (l = r)) to apply. *)
(* ------------------------------------------------------------------------- *)
let ORDERED_REWR_CONV ord th =
let basic_conv = REWR_CONV th in
fun tm ->
let thm = basic_conv tm in
let l,r = dest_eq(concl thm) in
if ord l r then thm
else failwith "ORDERED_REWR_CONV: wrong orientation";;
let ORDERED_IMP_REWR_CONV ord th =
let basic_conv = IMP_REWR_CONV th in
fun tm ->
let thm = basic_conv tm in
let l,r = dest_eq(rand(concl thm)) in
if ord l r then thm
else failwith "ORDERED_IMP_REWR_CONV: wrong orientation";;
(* ------------------------------------------------------------------------- *)
(* Standard AC-compatible term ordering: a "dynamic" lexicographic ordering. *)
(* *)
(* This is a slight hack to make AC normalization work. However I *think* *)
(* it's properly AC compatible, i.e. monotonic and total, WF on ground terms *)
(* (over necessarily finite signature) and with the properties for any *)
(* binary operator +: *)
(* *)
(* (x + y) + z > x + (y + z) *)
(* x + y > y + x iff x > y *)
(* x + (y + z) > y + (x + z) iff x > y *)
(* *)
(* The idea is that when invoking lex ordering with identical head operator *)
(* "f", one sticks "f" at the head of an otherwise arbitrary ordering on *)
(* subterms (the built-in CAML one). This avoids the potentially inefficient *)
(* calculation of term size in the standard orderings. *)
(* ------------------------------------------------------------------------- *)
let term_order =
let rec lexify ord l1 l2 =
if l1 = [] then false
else if l2 = [] then true else
let h1 = hd l1 and h2 = hd l2 in
ord h1 h2 || (h1 = h2 && lexify ord (tl l1) (tl l2)) in
let rec dyn_order top tm1 tm2 =
let f1,args1 = strip_comb tm1
and f2,args2 = strip_comb tm2 in
if f1 = f2 then
lexify (dyn_order f1) args1 args2
else
if f2 = top then false
else if f1 = top then true
else f1 > f2 in
dyn_order `T`;;
(* ------------------------------------------------------------------------- *)
(* Create a gconv net for a theorem as a (cond) rewrite. The "rep" flag *)
(* will cause any trivially looping rewrites to be modified, and any that *)
(* are permutative to be ordered w.r.t. the standard order. The idea is that *)
(* this flag will be set iff the conversion is going to get repeated. *)
(* This includes a completely ad hoc but useful special case for ETA_AX, *)
(* which forces a first order match (otherwise it would loop on a lambda). *)
(* ------------------------------------------------------------------------- *)
let net_of_thm rep th =
let tm = concl th in
let lconsts = freesl (hyp th) in
let matchable = can o term_match lconsts in
match tm with
Comb(Comb(Const("=",_),(Abs(x,Comb(Var(s,ty) as v,x')) as l)),v')
when x' = x && v' = v && not(x = v) ->
let conv tm =
match tm with
Abs(y,Comb(t,y')) when y = y' && not(free_in y t) ->
INSTANTIATE(term_match [] v t) th
| _ -> failwith "REWR_CONV (ETA_AX special case)" in
enter lconsts (l,(1,conv))
| Comb(Comb(Const("=",_),l),r) ->
if rep && free_in l r then
let th' = EQT_INTRO th in
enter lconsts (l,(1,REWR_CONV th'))
else if rep && matchable l r && matchable r l then
enter lconsts (l,(1,ORDERED_REWR_CONV term_order th))
else enter lconsts (l,(1,REWR_CONV th))
| Comb(Comb(_,t),Comb(Comb(Const("=",_),l),r)) ->
if rep && free_in l r then
let th' = DISCH t (EQT_INTRO(UNDISCH th)) in
enter lconsts (l,(3,IMP_REWR_CONV th'))
else if rep && matchable l r && matchable r l then
enter lconsts (l,(3,ORDERED_IMP_REWR_CONV term_order th))
else enter lconsts(l,(3,IMP_REWR_CONV th));;
(* ------------------------------------------------------------------------- *)
(* Create a gconv net for a conversion with a term index. *)
(* ------------------------------------------------------------------------- *)
let net_of_conv tm conv sofar =
enter [] (tm,(2,conv)) sofar;;
(* ------------------------------------------------------------------------- *)
(* Create a gconv net for a congruence rule (in canonical form!) *)
(* ------------------------------------------------------------------------- *)
let net_of_cong th sofar =
let conc,n = repeat (fun (tm,m) -> snd(dest_imp tm),m+1) (concl th,0) in
if n = 0 then failwith "net_of_cong: Non-implicational congruence" else
let pat = lhs conc in
let conv = GEN_PART_MATCH (lhand o funpow n rand) th in
enter [] (pat,(4,conv)) sofar;;
(* ------------------------------------------------------------------------- *)
(* Rewrite maker for ordinary and conditional rewrites (via "cf" flag). *)
(* *)
(* We follow Don in going from ~(s = t) to (s = t) = F *and* (t = s) = F. *)
(* Well, why not? However, we don't abandon s = t where FV(t) is not a *)
(* subset of FV(s) in favour of (s = t) = T, as he does. *)
(* Note: looping rewrites are not discarded here, only when netted. *)
(* ------------------------------------------------------------------------- *)
let mk_rewrites =
let IMP_CONJ_CONV = REWR_CONV(ITAUT `p ==> q ==> r <=> p /\ q ==> r`)
and IMP_EXISTS_RULE =
let cnv = REWR_CONV(ITAUT `(!x. P x ==> Q) <=> (?x. P x) ==> Q`) in
fun v th -> CONV_RULE cnv (GEN v th) in
let collect_condition oldhyps th =
let conds = subtract (hyp th) oldhyps in
if conds = [] then th else
let jth = itlist DISCH conds th in
let kth = CONV_RULE (REPEATC IMP_CONJ_CONV) jth in
let cond,eqn = dest_imp(concl kth) in
let fvs = subtract (subtract (frees cond) (frees eqn)) (freesl oldhyps) in
itlist IMP_EXISTS_RULE fvs kth in
let rec split_rewrites oldhyps cf th sofar =
let tm = concl th in
if is_forall tm then
split_rewrites oldhyps cf (SPEC_ALL th) sofar
else if is_conj tm then
split_rewrites oldhyps cf (CONJUNCT1 th)
(split_rewrites oldhyps cf (CONJUNCT2 th) sofar)
else if is_imp tm && cf then
split_rewrites oldhyps cf (UNDISCH th) sofar
else if is_eq tm then
(if cf then collect_condition oldhyps th else th)::sofar
else if is_neg tm then
let ths = split_rewrites oldhyps cf (EQF_INTRO th) sofar in
if is_eq (rand tm)
then split_rewrites oldhyps cf (EQF_INTRO (GSYM th)) ths
else ths
else
split_rewrites oldhyps cf (EQT_INTRO th) sofar in
fun cf th sofar -> split_rewrites (hyp th) cf th sofar;;
(* ------------------------------------------------------------------------- *)
(* Rewriting (and application of other conversions) based on a convnet. *)
(* ------------------------------------------------------------------------- *)
let REWRITES_CONV net tm =
let pconvs = lookup tm net in
try tryfind (fun (_,cnv) -> cnv tm) pconvs
with Failure _ -> failwith "REWRITES_CONV";;
(* ------------------------------------------------------------------------- *)
(* Decision procedures may accumulate their state in different ways (e.g. *)
(* term nets and predicate-indexed lists of Horn clauses). To allow mixing *)
(* of arbitrary types for state storage, we use a trick due to RJB via DRS. *)
(* ------------------------------------------------------------------------- *)
type prover = Prover of conv * (thm list -> prover);;
let mk_prover applicator augmentor =
let rec mk_prover state =
let apply = applicator state
and augment thms = mk_prover (augmentor state thms) in
Prover(apply,augment) in
mk_prover;;
let augment(Prover(_,aug)) thms = aug thms;;
let apply_prover(Prover(conv,_)) tm = conv tm;;
(* ------------------------------------------------------------------------- *)
(* Type of simpsets. We have a convnet containing rewrites (implicational *)
(* and otherwise), other term-indexed context-free conversions like *)
(* BETA_CONV, and congruence rules. Then there is a list of provers that *)
(* have their own way of storing and using context, and finally a rewrite *)
(* maker function, to allow customization. *)
(* *)
(* We also have a type of (traversal) strategy, following Konrad. *)
(* ------------------------------------------------------------------------- *)
type simpset =
Simpset of gconv net (* Rewrites & congruences *)
* (strategy -> strategy) (* Prover for conditions *)
* prover list (* Subprovers for prover *)
* (thm -> thm list -> thm list) (* Rewrite maker *)
and strategy = simpset -> int -> term -> thm;;
(* ------------------------------------------------------------------------- *)
(* Very simple prover: recursively simplify then try provers. *)
(* ------------------------------------------------------------------------- *)
let basic_prover strat (Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let sth = try strat ss lev tm with Failure _ -> REFL tm in
try EQT_ELIM sth
with Failure _ ->
let tth = tryfind (fun pr -> apply_prover pr (rand(concl sth))) provers in
EQ_MP (SYM sth) tth;;
(* ------------------------------------------------------------------------- *)
(* Functions for changing or augmenting components of simpsets. *)
(* ------------------------------------------------------------------------- *)
let ss_of_thms thms (Simpset(net,prover,provers,rewmaker)) =
let cthms = itlist rewmaker thms [] in
let net' = itlist (net_of_thm true) cthms net in
Simpset(net',prover,provers,rewmaker);;
let ss_of_conv keytm conv (Simpset(net,prover,provers,rewmaker)) =
let net' = net_of_conv keytm conv net in
Simpset(net',prover,provers,rewmaker);;
let ss_of_congs thms (Simpset(net,prover,provers,rewmaker)) =
let net' = itlist net_of_cong thms net in
Simpset(net',prover,provers,rewmaker);;
let ss_of_prover newprover (Simpset(net,_,provers,rewmaker)) =
Simpset(net,newprover,provers,rewmaker);;
let ss_of_provers newprovers (Simpset(net,prover,provers,rewmaker)) =
Simpset(net,prover,newprovers@provers,rewmaker);;
let ss_of_maker newmaker (Simpset(net,prover,provers,_)) =
Simpset(net,prover,provers,newmaker);;
(* ------------------------------------------------------------------------- *)
(* Perform a context-augmentation operation on a simpset. *)
(* ------------------------------------------------------------------------- *)
let AUGMENT_SIMPSET cth (Simpset(net,prover,provers,rewmaker)) =
let provers' = map (C augment [cth]) provers in
let cthms = rewmaker cth [] in
let net' = itlist (net_of_thm true) cthms net in
Simpset(net',prover,provers',rewmaker);;
(* ------------------------------------------------------------------------- *)
(* Depth conversions. *)
(* ------------------------------------------------------------------------- *)
let ONCE_DEPTH_SQCONV,DEPTH_SQCONV,REDEPTH_SQCONV,
TOP_DEPTH_SQCONV,TOP_SWEEP_SQCONV =
let IMP_REWRITES_CONV strat (Simpset(net,prover,provers,rewmaker) as ss) lev
pconvs tm =
tryfind (fun (n,cnv) ->
if n >= 4 then fail() else
let th = cnv tm in
let etm = concl th in
if is_eq etm then th else
if lev <= 0 then failwith "IMP_REWRITES_CONV: Too deep" else
let cth = prover strat ss (lev-1) (lhand etm) in
MP th cth) pconvs in
let rec RUN_SUB_CONV strat ss lev triv th =
let tm = concl th in
if is_imp tm then
let subtm = lhand tm in
let avs,bod = strip_forall subtm in
let (t,t'),ss',mk_fun =
try dest_eq bod,ss,I with Failure _ ->
let cxt,deq = dest_imp bod in
dest_eq deq,AUGMENT_SIMPSET (ASSUME cxt) ss,DISCH cxt in
let eth,triv' = try strat ss' lev t,false with Failure _ -> REFL t,triv in
let eth' = GENL avs (mk_fun eth) in
let th' = if is_var t' then INST [rand(concl eth),t'] th
else GEN_PART_MATCH lhand th (concl eth') in
let th'' = MP th' eth' in
RUN_SUB_CONV strat ss lev triv' th''
else if triv then fail() else th in
let GEN_SUB_CONV strat ss lev pconvs tm =
try tryfind (fun (n,cnv) ->
if n < 4 then fail() else
let th = cnv tm in
RUN_SUB_CONV strat ss lev true th) pconvs
with Failure _ ->
if is_comb tm then
let l,r = dest_comb tm in
try let th1 = strat ss lev l in
try let th2 = strat ss lev r in MK_COMB(th1,th2)
with Failure _ -> AP_THM th1 r
with Failure _ -> AP_TERM l (strat ss lev r)
else if is_abs tm then
let v,bod = dest_abs tm in
let th = strat ss lev bod in
try ABS v th with Failure _ ->
let gv = genvar(type_of v) in
let gbod = vsubst[gv,v] bod in
let gth = ABS gv (strat ss lev gbod) in
let gtm = concl gth in
let l,r = dest_eq gtm in
let v' = variant (frees gtm) v in
let l' = alpha v' l and r' = alpha v' r in
EQ_MP (ALPHA gtm (mk_eq(l',r'))) gth
else failwith "GEN_SUB_CONV" in
let rec ONCE_DEPTH_SQCONV
(Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let pconvs = lookup tm net in
try IMP_REWRITES_CONV ONCE_DEPTH_SQCONV ss lev pconvs tm
with Failure _ ->
GEN_SUB_CONV ONCE_DEPTH_SQCONV ss lev pconvs tm in
let rec DEPTH_SQCONV (Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let pconvs = lookup tm net in
try let th1 = GEN_SUB_CONV DEPTH_SQCONV ss lev pconvs tm in
let tm1 = rand(concl th1) in
let pconvs1 = lookup tm1 net in
try TRANS th1 (IMP_REWRITES_CONV DEPTH_SQCONV ss lev pconvs1 tm1)
with Failure _ -> th1
with Failure _ ->
IMP_REWRITES_CONV DEPTH_SQCONV ss lev pconvs tm in
let rec REDEPTH_SQCONV (Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let pconvs = lookup tm net in
let th =
try let th1 = GEN_SUB_CONV REDEPTH_SQCONV ss lev pconvs tm in
let tm1 = rand(concl th1) in
let pconvs1 = lookup tm1 net in
try TRANS th1 (IMP_REWRITES_CONV REDEPTH_SQCONV ss lev pconvs1 tm1)
with Failure _ -> th1
with Failure _ ->
IMP_REWRITES_CONV REDEPTH_SQCONV ss lev pconvs tm in
try let th' = REDEPTH_SQCONV ss lev (rand(concl th)) in
TRANS th th'
with Failure _ -> th in
let rec TOP_DEPTH_SQCONV (Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let pconvs = lookup tm net in
let th1 =
try IMP_REWRITES_CONV TOP_DEPTH_SQCONV ss lev pconvs tm
with Failure _ -> GEN_SUB_CONV TOP_DEPTH_SQCONV ss lev pconvs tm in
try let th2 = TOP_DEPTH_SQCONV ss lev (rand(concl th1)) in
TRANS th1 th2
with Failure _ -> th1 in
let rec TOP_SWEEP_SQCONV (Simpset(net,prover,provers,rewmaker) as ss) lev tm =
let pconvs = lookup tm net in
try let th1 = IMP_REWRITES_CONV TOP_SWEEP_SQCONV ss lev pconvs tm in
try let th2 = TOP_SWEEP_SQCONV ss lev (rand(concl th1)) in
TRANS th1 th2
with Failure _ -> th1
with Failure _ -> GEN_SUB_CONV TOP_SWEEP_SQCONV ss lev pconvs tm in
ONCE_DEPTH_SQCONV,DEPTH_SQCONV,REDEPTH_SQCONV,
TOP_DEPTH_SQCONV,TOP_SWEEP_SQCONV;;
(* ------------------------------------------------------------------------- *)
(* Maintenence of basic rewrites and conv nets for rewriting. *)
(* ------------------------------------------------------------------------- *)
let set_basic_rewrites,extend_basic_rewrites,basic_rewrites,
set_basic_convs,extend_basic_convs,basic_convs,basic_net =
let rewrites = ref ([]:thm list)
and conversions = ref ([]:(string*(term*conv))list)
and conv_net = ref (empty_net: gconv net) in
let rehash_convnet() =
conv_net := itlist (net_of_thm true) (!rewrites)
(itlist (fun (_,(pat,cnv)) -> net_of_conv pat cnv) (!conversions)
empty_net) in
let set_basic_rewrites thl =
let canon_thl = itlist (mk_rewrites false) thl [] in
(rewrites := canon_thl; rehash_convnet())
and extend_basic_rewrites thl =
let canon_thl = itlist (mk_rewrites false) thl [] in
(rewrites := canon_thl @ !rewrites; rehash_convnet())
and basic_rewrites() = !rewrites
and set_basic_convs cnvs =
(conversions := cnvs; rehash_convnet())
and extend_basic_convs (name,patcong) =
(conversions :=
(name,patcong)::filter(fun (name',_) -> name <> name') (!conversions);
rehash_convnet())
and basic_convs() = !conversions
and basic_net() = !conv_net in
set_basic_rewrites,extend_basic_rewrites,basic_rewrites,
set_basic_convs,extend_basic_convs,basic_convs,basic_net;;
(* ------------------------------------------------------------------------- *)
(* Same thing for the default congruences. *)
(* ------------------------------------------------------------------------- *)
let set_basic_congs,extend_basic_congs,basic_congs =
let congs = ref ([]:thm list) in
(fun thl -> congs := thl),
(fun thl -> congs := union' equals_thm thl (!congs)),
(fun () -> !congs);;
(* ------------------------------------------------------------------------- *)
(* Main rewriting conversions. *)
(* ------------------------------------------------------------------------- *)
let GENERAL_REWRITE_CONV rep (cnvl:conv->conv) (builtin_net:gconv net) thl =
let thl_canon = itlist (mk_rewrites false) thl [] in
let final_net = itlist (net_of_thm rep) thl_canon builtin_net in
cnvl (REWRITES_CONV final_net);;
let GEN_REWRITE_CONV (cnvl:conv->conv) thl =
GENERAL_REWRITE_CONV false cnvl empty_net thl;;
let PURE_REWRITE_CONV thl =
GENERAL_REWRITE_CONV true TOP_DEPTH_CONV empty_net thl;;
let REWRITE_CONV thl =
GENERAL_REWRITE_CONV true TOP_DEPTH_CONV (basic_net()) thl;;
let PURE_ONCE_REWRITE_CONV thl =
GENERAL_REWRITE_CONV false ONCE_DEPTH_CONV empty_net thl;;
let ONCE_REWRITE_CONV thl =
GENERAL_REWRITE_CONV false ONCE_DEPTH_CONV (basic_net()) thl;;
(* ------------------------------------------------------------------------- *)
(* Rewriting rules and tactics. *)
(* ------------------------------------------------------------------------- *)
let GEN_REWRITE_RULE cnvl thl = CONV_RULE(GEN_REWRITE_CONV cnvl thl);;
let PURE_REWRITE_RULE thl = CONV_RULE(PURE_REWRITE_CONV thl);;
let REWRITE_RULE thl = CONV_RULE(REWRITE_CONV thl);;
let PURE_ONCE_REWRITE_RULE thl = CONV_RULE(PURE_ONCE_REWRITE_CONV thl);;
let ONCE_REWRITE_RULE thl = CONV_RULE(ONCE_REWRITE_CONV thl);;
let PURE_ASM_REWRITE_RULE thl th =
PURE_REWRITE_RULE ((map ASSUME (hyp th)) @ thl) th;;
let ASM_REWRITE_RULE thl th =
REWRITE_RULE ((map ASSUME (hyp th)) @ thl) th;;
let PURE_ONCE_ASM_REWRITE_RULE thl th =
PURE_ONCE_REWRITE_RULE ((map ASSUME (hyp th)) @ thl) th;;
let ONCE_ASM_REWRITE_RULE thl th =
ONCE_REWRITE_RULE ((map ASSUME (hyp th)) @ thl) th;;
let GEN_REWRITE_TAC cnvl thl = CONV_TAC(GEN_REWRITE_CONV cnvl thl);;
let PURE_REWRITE_TAC thl = CONV_TAC(PURE_REWRITE_CONV thl);;
let REWRITE_TAC thl = CONV_TAC(REWRITE_CONV thl);;
let PURE_ONCE_REWRITE_TAC thl = CONV_TAC(PURE_ONCE_REWRITE_CONV thl);;
let ONCE_REWRITE_TAC thl = CONV_TAC(ONCE_REWRITE_CONV thl);;
let (PURE_ASM_REWRITE_TAC: thm list -> tactic) =
ASM PURE_REWRITE_TAC;;
let (ASM_REWRITE_TAC: thm list -> tactic) =
ASM REWRITE_TAC;;
let (PURE_ONCE_ASM_REWRITE_TAC: thm list -> tactic) =
ASM PURE_ONCE_REWRITE_TAC;;
let (ONCE_ASM_REWRITE_TAC: thm list -> tactic) =
ASM ONCE_REWRITE_TAC;;
(* ------------------------------------------------------------------------- *)
(* Simplification functions. *)
(* ------------------------------------------------------------------------- *)
let GEN_SIMPLIFY_CONV (strat:strategy) ss lev thl =
let ss' = itlist AUGMENT_SIMPSET thl ss in
TRY_CONV (strat ss' lev);;
let ONCE_SIMPLIFY_CONV ss = GEN_SIMPLIFY_CONV ONCE_DEPTH_SQCONV ss 1;;
let SIMPLIFY_CONV ss = GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV ss 3;;
(* ------------------------------------------------------------------------- *)
(* Simple but useful default version. *)
(* ------------------------------------------------------------------------- *)
let empty_ss = Simpset(empty_net,basic_prover,[],mk_rewrites true);;
let basic_ss =
let rewmaker = mk_rewrites true in
fun thl ->
let cthms = itlist rewmaker thl [] in
let net' = itlist (net_of_thm true) cthms (basic_net()) in
let net'' = itlist net_of_cong (basic_congs()) net' in
Simpset(net'',basic_prover,[],rewmaker);;
let SIMP_CONV thl = SIMPLIFY_CONV (basic_ss []) thl;;
let PURE_SIMP_CONV thl = SIMPLIFY_CONV empty_ss thl;;
let ONCE_SIMP_CONV thl = ONCE_SIMPLIFY_CONV (basic_ss []) thl;;
let SIMP_RULE thl = CONV_RULE(SIMP_CONV thl);;
let PURE_SIMP_RULE thl = CONV_RULE(PURE_SIMP_CONV thl);;
let ONCE_SIMP_RULE thl = CONV_RULE(ONCE_SIMP_CONV thl);;
let SIMP_TAC thl = CONV_TAC(SIMP_CONV thl);;
let PURE_SIMP_TAC thl = CONV_TAC(PURE_SIMP_CONV thl);;
let ONCE_SIMP_TAC thl = CONV_TAC(ONCE_SIMP_CONV thl);;
let ASM_SIMP_TAC = ASM SIMP_TAC;;
let PURE_ASM_SIMP_TAC = ASM PURE_SIMP_TAC;;
let ONCE_ASM_SIMP_TAC = ASM ONCE_SIMP_TAC;;
(* ------------------------------------------------------------------------- *)
(* Abbreviation tactics. *)
(* ------------------------------------------------------------------------- *)
let ABBREV_TAC tm =
let cvs,t = dest_eq tm in
let v,vs = strip_comb cvs in
let rs = list_mk_abs(vs,t) in
let eq = mk_eq(rs,v) in
let th1 = itlist (fun v th -> CONV_RULE(LAND_CONV BETA_CONV) (AP_THM th v))
(rev vs) (ASSUME eq) in
let th2 = SIMPLE_CHOOSE v (SIMPLE_EXISTS v (GENL vs th1)) in
let th3 = PROVE_HYP (EXISTS(mk_exists(v,eq),rs) (REFL rs)) th2 in
fun (asl,w as gl) ->
let avoids = itlist (union o frees o concl o snd) asl (frees w) in
if mem v avoids then failwith "ABBREV_TAC: variable already used" else
CHOOSE_THEN
(fun th -> RULE_ASSUM_TAC(PURE_ONCE_REWRITE_RULE[th]) THEN
PURE_ONCE_REWRITE_TAC[th] THEN
ASSUME_TAC th)
th3 gl;;
let EXPAND_TAC s = FIRST_ASSUM(SUBST1_TAC o SYM o
check((=) s o fst o dest_var o rhs o concl)) THEN BETA_TAC;;