1290650Shselasky(* ===================================================================== *)
2290650Shselasky(* FILE          : dep_rewrite.sml                                       *)
3290650Shselasky(* VERSION       : 1.1                                                   *)
4290650Shselasky(* DESCRIPTION   : Dependent Rewriting Tactics (general purpose)         *)
5290650Shselasky(*                                                                       *)
6290650Shselasky(* AUTHOR        : Peter Vincent Homeier                                 *)
7290650Shselasky(* DATE          : May 7, 2002                                           *)
8290650Shselasky(* COPYRIGHT     : Copyright (c) 2002 by Peter Vincent Homeier           *)
9290650Shselasky(*                                                                       *)
10290650Shselasky(* ===================================================================== *)
11290650Shselasky
12290650Shselasky(* ================================================================== *)
13290650Shselasky(* ================================================================== *)
14290650Shselasky(*                     DEPENDENT REWRITING TACTICS                    *)
15290650Shselasky(* ================================================================== *)
16290650Shselasky(* ================================================================== *)
17290650Shselasky(*                                                                    *)
18290650Shselasky(* This file contains new tactics for dependent rewriting,            *)
19290650Shselasky(* a generalization of the rewriting tactics of standard HOL.         *)
20290650Shselasky(*                                                                    *)
21290650Shselasky(* The main tactics are named DEP_REWRITE_TAC[thm1,...], etc., with   *)
22290650Shselasky(* the standard variations (PURE,ONCE,ASM).  In addition, tactics     *)
23290650Shselasky(* with LIST instead of ONCE are provided, making 12 tactics in all.  *)
24290650Shselasky(*                                                                    *)
25290650Shselasky(* The argument theorems thm1,... are typically implications.         *)
26290650Shselasky(* These tactics identify the consequents of the argument theorems,   *)
27290650Shselasky(* and attempt to match these against the current goal.  If a match   *)
28290650Shselasky(* is found, the goal is rewritten according to the matched instance  *)
29290650Shselasky(* of the consequent, after which the corresponding hypotheses of     *)
30290650Shselasky(* the argument theorems are added to the goal as new conjuncts on    *)
31290650Shselasky(* the left.                                                          *)
32290650Shselasky(*                                                                    *)
33290650Shselasky(* Care needs to be taken that the implications will match the goal   *)
34290650Shselasky(* properly, that is, instances where the hypotheses in fact can be   *)
35290650Shselasky(* proven.  Also, even more commonly than with REWRITE_TAC,           *)
36290650Shselasky(* the rewriting process may diverge.                                 *)
37290650Shselasky(*                                                                    *)
38290650Shselasky(* Each implication theorem for rewriting may have a layer of         *)
39290650Shselasky(* universal quantifications, under which is the base, which will     *)
40290650Shselasky(* either be an equality, a negation, or a general term.  The pattern *)
41290650Shselasky(* for matching will be the left-hand-side of an equality, the term   *)
42290650Shselasky(* negated of a negation, or the term itself in the third case.  The  *)
43290650Shselasky(* search is top-to-bottom, left-to-right, depending on the           *)
44290650Shselasky(* quantifications of variables.                                      *)
45290650Shselasky(*                                                                    *)
46290650Shselasky(* To assist in focusing the matching to useful cases, the goal is    *)
47290650Shselasky(* searched for a subterm matching the pattern.  The matching of the  *)
48290650Shselasky(* pattern to subterms is performed by higher-order matching, so for  *)
49290650Shselasky(* example, ``!x. P x`` will match the term ``!n. (n+m) < 4*n``.      *)
50290650Shselasky(*                                                                    *)
51290650Shselasky(* The argument theorems may each be either an implication or not.    *)
52290650Shselasky(* For those which are implications, the hypotheses of the instance   *)
53290650Shselasky(* of each theorem which matched the goal are added to the goal as    *)
54290650Shselasky(* conjuncts on the left side.  For those argument theorems which     *)
55290650Shselasky(* are not implications, the goal is simply rewritten with them.      *)
56290650Shselasky(* This rewriting is also higher order.                               *)
57290650Shselasky(*                                                                    *)
58290650Shselasky(* As much as possible, the newly added hypotheses are analyzed to    *)
59290650Shselasky(* remove duplicates; thus, several theorems with the same            *)
60290650Shselasky(* hypothesis, or several uses of the same theorem, will generate     *)
61290650Shselasky(* a minimal additional proof burden.                                 *)
62290650Shselasky(*                                                                    *)
63290650Shselasky(* The new hypotheses are added as conjuncts rather than as a         *)
64290650Shselasky(* separate subgoal to reduce the user's burden of subgoal splits     *)
65290650Shselasky(* when creating tactics to prove theorems.  If a separate subgoal    *)
66290650Shselasky(* is desired, simply use CONJ_TAC after the dependent rewriting to   *)
67290650Shselasky(* split the goal into two, where the first contains the hypotheses   *)
68290650Shselasky(* and the second contains the rewritten version of the original      *)
69290650Shselasky(* goal.                                                              *)
70290650Shselasky(*                                                                    *)
71290650Shselasky(* The tactics including PURE in their name will only use the         *)
72290650Shselasky(* listed theorems for all rewriting; otherwise, the standard         *)
73290650Shselasky(* rewrites are used for normal rewriting, but they are not           *)
74290650Shselasky(* considered for dependent rewriting.                                *)
75290650Shselasky(*                                                                    *)
76290650Shselasky(* The tactics including ONCE in their name attempt to use each       *)
77290650Shselasky(* theorem in the list, only once, in order, left to right.           *)
78290650Shselasky(* The hypotheses added in the process of dependent rewriting are     *)
79290650Shselasky(* not rewritten by the ONCE tactics.  This gives a more restrained   *)
80290650Shselasky(* version of dependent rewriting.                                    *)
81290650Shselasky(*                                                                    *)
82290650Shselasky(* The tactics with LIST take a list of lists of theorems, and        *)
83290650Shselasky(* uses each list of theorems once in order, left-to-right.  For      *)
84290650Shselasky(* each list of theorems, the goal is rewritten as much as possible,  *)
85290650Shselasky(* until no further changes can be achieved in the goal.  Hypotheses  *)
86290650Shselasky(* are collected from all rewriting and added to the goal, but they   *)
87290650Shselasky(* are not themselves rewritten.                                      *)
88290650Shselasky(*                                                                    *)
89290650Shselasky(* The tactics without ONCE or LIST attempt to reuse all theorems     *)
90290650Shselasky(* repeatedly, continuing to rewrite until no changes can be          *)
91290650Shselasky(* achieved in the goal.  Hypotheses are rewritten as well, and       *)
92290650Shselasky(* their hypotheses as well, ad infinitum.                            *)
93290650Shselasky(*                                                                    *)
94290650Shselasky(* The tactics with ASM in their name add the assumption list to      *)
95290650Shselasky(* the list of theorems used for dependent rewriting.                 *)
96290650Shselasky(*                                                                    *)
97290650Shselasky(* There are also three more general tactics provided,                *)
98290650Shselasky(* DEP_FIND_THEN, DEP_ONCE_FIND_THEN, and DEP_LIST_FIND_THEN,         *)
99290650Shselasky(* from which the others are constructed.                             *)
100290650Shselasky(*                                                                    *)
101290650Shselasky(* The differences among these is that DEP_ONCE_FIND_THEN uses        *)
102290650Shselasky(* each of its theorems only once, in order left-to-right as given,   *)
103290650Shselasky(* whereas DEP_FIND_THEN continues to reuse its theorems repeatedly   *)
104290650Shselasky(* as long as forward progress and change is possible.  In contrast   *)
105290650Shselasky(* to the others, DEP_LIST_FIND_THEN takes as its argument a list     *)
106290650Shselasky(* of lists of theorems, and processes these in order, left-to-right. *)
107290650Shselasky(* For each list of theorems, the goal is rewritten as many times     *)
108290650Shselasky(* as they apply.  The hypotheses for all these rewritings are        *)
109290650Shselasky(* collected into one set, added to the goal after all rewritings.    *)
110290650Shselasky(*                                                                    *)
111290650Shselasky(* DEP_ONCE_FIND_THEN and DEP_LIST_FIND_THEN will not attack the      *)
112290650Shselasky(* hypotheses generated as a byproduct of the dependent rewriting;    *)
113290650Shselasky(* in contrast, DEP_FIND_THEN will.  DEP_ONCE_FIND_THEN and           *)
114290650Shselasky(* DEP_LIST_FIND_THEN might be fruitfully applied again to their      *)
115290650Shselasky(* results; DEP_FIND_THEN will complete any possible rewriting,       *)
116290650Shselasky(* and need not be reapplied.                                         *)
117290650Shselasky(*                                                                    *)
118290650Shselasky(* These take as argument a thm_tactic, a function which takes a      *)
119290650Shselasky(* theorem and yields a tactic.  It is this which is used to apply    *)
120290650Shselasky(* the instantiated consequent of each successfully matched           *)
121290650Shselasky(* implication to the current goal.  Usually this is something like   *)
122290650Shselasky(* (fn th => REWRITE_TAC[th]), but the user is free to supply any     *)
123290650Shselasky(* thm_tactic he wishes.                                              *)
124290650Shselasky(*                                                                    *)
125290650Shselasky(* One significant note: because of the strategy of adding new        *)
126290650Shselasky(* hypotheses as conjuncts to the current goal, it is not fruitful    *)
127290650Shselasky(* to add *any* new assumptions to the current goal, as one might     *)
128290650Shselasky(* think would happen from using, say, ASSUME_TAC.                    *)
129290650Shselasky(*                                                                    *)
130290650Shselasky(* Rather, any such new assumptions introduced by thm_tactic are      *)
131290650Shselasky(* specifically removed.  Instead, one might wish to try MP_TAC,      *)
132290650Shselasky(* which will have the effect of ASSUME_TAC and then undischarging    *)
133290650Shselasky(* that assumption to become an antecedent of the goal.  Other        *)
134290650Shselasky(* thm_tactics may be used, and they may even convert the single      *)
135290650Shselasky(* current subgoal into multiple subgoals.  If this happens, it is    *)
136290650Shselasky(* fine, but note that the control strategy of DEP_FIND_THEN will     *)
137290650Shselasky(* continue to attack only the first of the multiple subgoals.        *)
138290650Shselasky(*                                                                    *)
139290650Shselasky(* ================================================================== *)
140290650Shselasky(* ================================================================== *)
141290650Shselasky
142290650Shselasky
143290650Shselaskystructure dep_rewrite :> dep_rewrite =
144290650Shselaskystruct
145290650Shselasky
146290650Shselaskyopen HolKernel Parse boolLib Abbrev;
147290650Shselasky
148290650Shselasky
149290650Shselasky
150290650Shselasky
151290650Shselaskylocal
152290650Shselasky
153290650Shselaskyval show_rewrites = ref false; (* normally false, set true for tracing   *)
154290650Shselasky
155290650Shselaskyval debug         = false;  (* normally false, set to true for debugging *)
156290650Shselaskyval debug_fail    = false;  (* normally false, set to true for debugging *)
157290650Shselaskyval debug_match   = false;  (* normally false, set to true for debugging *)
158290650Shselaskyval debug_matches = false;  (* normally false, set to true for debugging *)
159290650Shselasky
160290650Shselasky(* Printing functions: (only needed for debugging) *)
161290650Shselaskyval print_string = TextIO.print;
162290650Shselaskyfun print_newline() = print_string "\n";
163290650Shselaskyfun print_strings []        = ()
164290650Shselasky   | print_strings (t :: []) = print_string t
165290650Shselasky   | print_strings (t :: ts) = (print_string t; print_string ",";
166290650Shselasky                                print_strings ts);
167fun print_theorem th = (print_string (thm_to_string th); print_newline());
168fun print_terms []        = ()
169   | print_terms (t :: []) = print_term t
170   | print_terms (t :: ts) = (print_term t; print_string ","; print_terms ts);
171fun print_all_thm th =
172   let val (ant,conseq) = dest_thm th
173   in (print_string "["; print_terms ant; print_string "] |- ";
174       print_term conseq; print_newline() )
175   end;
176fun print_theorems []        = ()
177   | print_theorems (t :: ts) = (print_theorem t; print_string "\n";
178                                 print_theorems ts);
179fun print_goal (asl,gl) = (print_term gl; print_newline());
180fun pthm th = (print_all_thm th; th);
181(**)
182
183fun TACTIC_ERR{function,message} =
184    Feedback.HOL_ERR{origin_structure = "Tactic",
185                      origin_function = function,
186                      message = message};
187
188fun failwith function =
189   ( (**) if debug_fail then
190         print_string ("Failure in dep_rewrite: "^function^"\n")
191     else (); (**)
192    raise TACTIC_ERR{function = function,message = "Failure in dep_rewrite"});
193
194
195
196fun UNDER_FORALL_CONV conv tm =
197    if is_forall tm then
198       RAND_CONV (ABS_CONV (UNDER_FORALL_CONV conv)) tm
199    else
200       conv tm ;
201
202(* Does multiple conversions of ==> to /\:
203val assemble_ants =
204      CONV_RULE (REPEATC (UNDER_FORALL_CONV RIGHT_IMP_FORALL_CONV)
205                 THENC UNDER_FORALL_CONV (REPEATC (REWR_CONV AND_IMP_INTRO)));
206*)
207
208val assemble_ants =
209      CONV_RULE (REPEATC (UNDER_FORALL_CONV RIGHT_IMP_FORALL_CONV)
210                 THENC UNDER_FORALL_CONV (TRY_CONV (REWR_CONV AND_IMP_INTRO)));
211
212(*
213assemble_ants EQ_LIST;
214*)
215
216(*
217val DEP_PENETRATE_CONV =
218    TOP_DEPTH_CONV RIGHT_IMP_FORALL_CONV
219    THENC PURE_REWRITE_CONV[AND_IMP_INTRO];
220
221val DEP_PENETRATE_RULE = CONV_RULE DEP_PENETRATE_CONV;
222
223val DEP_PENETRATE_ASSUM_TAC =
224    RULE_ASSUM_TAC DEP_PENETRATE_RULE;
225
226val DEP_PENETRATE_TAC =
227    CONV_TAC DEP_PENETRATE_CONV
228    THEN DEP_PENETRATE_ASSUM_TAC;
229*)
230
231
232fun UNDISCH_NOT_NEG th =
233  MP th (ASSUME(fst(dest_imp_only(concl th))))
234  handle HOL_ERR  _ => failwith "UNDISCH_NOT_NEG";
235
236fun UNDISCH_ALL_NOT_NEG th =
237    if is_imp_only(concl th)
238       then UNDISCH_ALL_NOT_NEG (UNDISCH_NOT_NEG th)
239       else th;
240
241
242fun DEP_FIND_matches th =
243   let
244       val tha = (* CONV_RULE (REPEATC
245                     (UNDER_FORALL_CONV RIGHT_IMP_FORALL_CONV)) *) th;
246       val tm = concl tha
247       val (avs,bod) = strip_forall tm
248       val (ants,conseq) = strip_imp_only bod
249       val th1 = SPECL avs (ASSUME tm)
250       val th2 = UNDISCH_ALL_NOT_NEG th1
251       val evs = filter(fn v => all (free_in v) ants
252                        andalso not(free_in v conseq)) avs
253       val th3 = itlist SIMPLE_CHOOSE evs (DISCH tm th2)
254       val hs = hyp th3
255       fun DISCH_ALL hyps th = itlist DISCH hyps th
256       val sth = MP (DISCH tm (GEN_ALL (DISCH_ALL hs (UNDISCH th3)))) tha
257       val term_to_match =
258              (lhs conseq
259               handle _ =>
260               dest_neg conseq
261               handle _ =>
262               conseq)
263  (*   val _ = (if !show_rewrites then
264                  (print_string "Searching for ";
265                   print_term term_to_match;
266                   print_string "\n")
267                  else ())   *)
268       val match_fn =
269           (HO_PART_MATCH (lhs o snd o strip_imp_only) sth
270            handle _ =>
271            HO_PART_MATCH (dest_neg o snd o strip_imp_only) sth
272            handle _ =>
273            HO_PART_MATCH (snd o strip_imp_only) sth)
274   in
275      match_fn
276   end
277   handle _ => failwith "DEP_FIND_matches: bad theorem";
278
279fun SUB_matches (f:term->'a) tm =
280   ( (* if debug_matches then (print_string "SUB_matches: ";
281                    print_term tm; print_newline()) else (); *)
282    if is_comb tm then
283       (let val {Rator,Rand} = Rsyntax.dest_comb tm in
284        (f Rator handle _ => f Rand)
285        end)
286    else
287    if is_abs tm then
288       let val {Bvar,Body} = Rsyntax.dest_abs tm in
289           f Body
290       end
291    else failwith "SUB_matches");
292
293fun ONCE_DEPTH_matches (f:term->'a) tm =
294     ( (* if debug_matches then
295        (print_string "ONCE_DEPTH_matches: "; print_term tm; print_newline())
296      else (); *)
297       (f tm handle _ => (SUB_matches (ONCE_DEPTH_matches f) tm)));
298
299
300
301
302(* ================================================================== *)
303(* APPLY_IMP_THEN ttac th is a dependent rewriting function,          *)
304(* which takes a goal and produce a 5-tuple containing:               *)
305(*                                                                    *)
306(*     assumption list,                                               *)
307(*     list of hypotheses,                                            *)
308(*     list of justification functions for those hypotheses,          *)
309(*     list of goals,                                                 *)
310(*     and list of justification functions for those goals.           *)
311(* ================================================================== *)
312
313local
314
315fun UNDISCH_ALL_NON_NEG th =
316   if (is_imp (concl th) andalso not(is_neg(concl th)))
317   then UNDISCH_ALL_NON_NEG (UNDISCH th)
318   else th;
319
320fun print_goals gl =
321   if null gl then print_string "proved\n"
322   else (map print_goal gl; ());
323
324fun repeat_apply (f:'a->'b) step stop x =
325      f x
326    handle (e as HOL_ERR _) =>
327      let val x' = step x in
328        if stop x x' then raise e
329        else repeat_apply f step stop x'
330      end;
331
332in
333
334fun APPLY_IMP_THEN ttac th (asl,gl) =
335    let val _ = if !show_rewrites then
336                   (print_string "Trying ";
337                    print_theorem th)
338                   else (); (**)
339        val matched =
340               repeat_apply
341                  (fn th => ONCE_DEPTH_matches (DEP_FIND_matches th) gl)
342                  assemble_ants
343                  (fn th1 => fn th2 => concl th1 ~~ concl th2)
344                  th;
345(*
346ONCE_DEPTH_matches (DEP_FIND_matches th) gl
347              handle e =>
348               let val th' = assemble_ants th in
349                if concl th' = concl th then raise e
350                else
351                  let val mtchd = ONCE_DEPTH_matches (DEP_FIND_matches th') gl
352                  in (if !show_rewrites then
353                        print_string "Found deeper match\n"
354                      else ();
355                      mtchd)
356                  end
357               end;
358*)
359(*      val _ = if !show_rewrites then
360                      (print_string "match found:\n";
361                       print_theorem matched)
362                   else (); *)
363        val base = UNDISCH_ALL_NON_NEG matched;
364        val subgoal = concl base;
365(**)    val _ = if !show_rewrites then
366                       (print_string "Rewriting ";
367                        print_term subgoal;
368                        print_string "\n")
369                   else (); (**)
370        val (gl1,p1) = ( (*REPEAT GEN_TAC THEN*)
371                          MATCH_MP_TAC matched) (asl,subgoal)
372        val (gl2,p2) = ttac (Thm.ASSUME subgoal) (asl,gl);
373    in
374     case gl1
375       of [(asl1,g1)] =>
376       ( if !show_rewrites then
377           (print_string "New burden: ";
378            print_goals gl1;
379            print_string "Revised goal: ";
380            print_goals gl2;
381            print_newline())
382          else ();
383         (asl1,[g1],[p1],gl2,p2) )
384        | _ => failwith "APPLY_IMP_THEN"
385    end
386
387end;
388
389(* ================================================================== *)
390(* We now introduce a series of tacticals for dependent rewriting     *)
391(* functions, which will be easily understood by relation to the      *)
392(* corresponding tacticals for tactics and conversions.               *)
393(* ================================================================== *)
394
395(* TAC_DEP turns a tactic into a dependent rewriting function. *)
396
397fun TAC_DEP tac = fn (asl,gl) =>
398    let val (gl0,p0) = tac (asl,gl)
399    in (asl,[],[],gl0,p0)
400    end
401    handle _ => failwith "TAC_DEP";
402
403
404
405(* DEP_TAC turns a dependent rewriting function into a tactic. *)
406
407fun DEP_TAC dep :tactic = fn g0 =>
408    let val (asl1,gls,(pls:validation list),(gl2:goal list),(p2:validation))
409            = dep g0 in
410    ( (* if debug then
411        (print_string "DEP_TAC:\nburdens = [";
412         map (fn tm => (print_newline(); print_term tm; print_string ",")) gls;
413         print_string "]\ncurrent goals = [";
414         map (fn g2 => (print_newline(); print_goal g2; print_string ",")) gl2;
415         print_string "]\n")
416    else (); *)
417    if null gls then (gl2,p2)
418    else
419    let
420        val rgls = op_mk_set aconv (flatten (map strip_conj gls));
421        val gl1 = [(asl1,list_mk_conj rgls)];
422        val p1 = (fn [th] =>
423                  map2 (fn gl => fn p =>
424                        p [( (* if debug then
425                               (print_string "Prove: ";
426                                print_term gl;
427                                print_newline();
428                                print_string "From: ";
429                                print_theorem th;
430                                print_newline())
431                            else (); *)
432                            TAC_PROOF
433                              (([], gl),
434                                  REPEAT CONJ_TAC
435                                  THEN FIRST(map ACCEPT_TAC (CONJUNCTS th)))
436                            handle _ => failwith "Burden proof failed"
437                                                     )]) gls pls
438                   | _ => failwith "DEP_TAC");
439    in
440      ( (* if debug then
441          (print_string "gl1 = \n"; print_goal (hd gl1))
442       else (); *)
443       case gl2
444         of [] =>
445           (gl1,(fn thl => itlist Drule.PROVE_HYP (p1 thl) (p2 [])))
446          | ((asl2,g2)::gl3) =>
447              case gl1 of
448                  [(asl1,g1)] =>
449                  ((op_intersect aconv asl1 asl2,
450                    Rsyntax.mk_conj{conj1=g1,conj2=g2})::gl3,
451                   (fn (tha::thl) =>
452                          itlist Drule.PROVE_HYP (p1 [CONJUNCT1 tha])
453                                                 (p2 ((CONJUNCT2 tha)::thl))
454                     | [] => failwith "DEP_TAC"))
455                 | _ => failwith "DEP_TAC"
456      )
457    end)
458    end
459    handle _ => failwith "DEP_TAC";
460
461
462
463fun choplist a b =
464   case a
465   of [] =>
466        ([],b)
467    | (h::t) =>
468        let val (c,d) = choplist t (tl b) in
469            ((hd b)::c, d)
470        end;
471
472infix THEN1_DEP;
473
474fun ctac1 THEN1_DEP ctac2 = fn g =>
475    let val (asl1,gs1,ps1,gl1,p1) = ctac1 g
476    in
477    case gl1
478    of [] =>
479         (asl1,gs1,ps1,gl1,p1)
480     | (g1::gl1') =>
481         let val (asl2,gs2,ps2,gl2,p2) = ctac2 g1
482         in
483         (op_intersect aconv asl1 asl2, gs1@gs2, ps1@ps2, gl2@gl1',
484          (fn ths => let val (ths1,ths2) = choplist gl2 ths in
485                          p1 ((p2 ths1) :: ths2)
486                     end))
487         end
488    end
489    handle HOL_ERR _ => failwith "THEN1_DEP";
490
491
492val ALL_DEP = fn (asl,gl) =>
493    (asl,[],[],[(asl,gl)],hd);
494
495
496infix ORELSE_DEP;
497
498fun ctac1 ORELSE_DEP ctac2 = fn g =>
499    ctac1 g handle HOL_ERR _ => ctac2 g;
500
501
502fun FIRST_DEP cl =
503    case cl
504    of [] =>
505         ALL_DEP
506     | (c::cl') =>
507         c ORELSE_DEP FIRST_DEP cl';
508
509
510fun EVERY_DEP cl =
511    case cl of
512        [] => ALL_DEP
513      | (c::cl') => c THEN1_DEP EVERY_DEP cl'
514    handle _ => failwith "EVERY_DEP";
515
516
517fun REPEAT_DEP ctac g =
518    ((ctac THEN1_DEP REPEAT_DEP ctac) ORELSE_DEP ALL_DEP) g;
519
520
521fun CHANGED_DEP ctac g =
522    let val (asl,gls,pls,gl,p) = ctac g in
523    if goals_eq gl [g] then failwith "CHANGED_DEP"
524    else (asl,gls,pls,gl,p)
525    end;
526
527
528
529(* We define theorem-tactics that take one theorem and rewrite with it. *)
530
531fun REWRITE_THM th = REWRITE_TAC[th];
532fun PURE_REWRITE_THM th = PURE_REWRITE_TAC[th];
533fun ONCE_REWRITE_THM th = ONCE_REWRITE_TAC[th];
534fun PURE_ONCE_REWRITE_THM th = PURE_ONCE_REWRITE_TAC[th];
535
536
537(* ================================================================== *)
538(* End of local declarations.                                         *)
539(* Beginning of exported declarations.                                *)
540(* ================================================================== *)
541
542in
543
544
545val show_rewrites = show_rewrites;
546
547
548(* ================================================================== *)
549(* ================================================================== *)
550(*                     DEPENDENT REWRITING TACTICS                    *)
551(* ================================================================== *)
552(* ================================================================== *)
553
554(* ================================================================== *)
555(*                                                                    *)
556(* The tactics including ONCE in their name attempt to use each       *)
557(* theorem in the list, only once, in order, left to right.           *)
558(* The hypotheses added in the process of dependent rewriting are     *)
559(* not rewritten by the ONCE tactics.  This gives a more fine-grain   *)
560(* control of dependent rewriting.                                    *)
561(*                                                                    *)
562(* ================================================================== *)
563
564
565
566fun DEP_ONCE_FIND_THEN (ttac:thm->tactic) ths :tactic =
567    DEP_TAC
568         (EVERY_DEP (map (fn th => APPLY_IMP_THEN ttac th
569                                    ORELSE_DEP TAC_DEP (ttac th))
570                          (flatten (map CONJUNCTS ths))))
571    handle _ => failwith "DEP_ONCE_FIND_THEN";
572
573
574
575val DEP_PURE_ONCE_REWRITE_TAC :(thm list)->tactic =
576    DEP_ONCE_FIND_THEN (fn th => Ho_Rewrite.PURE_ONCE_REWRITE_TAC[th]);
577
578fun DEP_ONCE_REWRITE_TAC thl :tactic =
579    DEP_PURE_ONCE_REWRITE_TAC thl
580    THEN Ho_Rewrite.REWRITE_TAC[];
581
582fun DEP_PURE_ONCE_ASM_REWRITE_TAC thl :tactic =
583    Tactical.ASSUM_LIST (fn asl => DEP_PURE_ONCE_REWRITE_TAC (asl @ thl));
584
585fun DEP_ONCE_ASM_REWRITE_TAC thl :tactic =
586    Tactical.ASSUM_LIST (fn asl => DEP_ONCE_REWRITE_TAC (asl @ thl));
587
588
589val DEP_PURE_ONCE_SUBST_TAC :(thm list)->tactic =
590    DEP_ONCE_FIND_THEN (fn th => SUBST1_TAC th ORELSE ALL_TAC);
591
592fun DEP_ONCE_SUBST_TAC thl :tactic =
593    DEP_PURE_ONCE_SUBST_TAC thl
594    THEN Ho_Rewrite.REWRITE_TAC[];
595
596fun DEP_PURE_ONCE_ASM_SUBST_TAC thl :tactic =
597    Tactical.ASSUM_LIST (fn asl => DEP_PURE_ONCE_SUBST_TAC (asl @ thl));
598
599fun DEP_ONCE_ASM_SUBST_TAC thl :tactic =
600    Tactical.ASSUM_LIST (fn asl => DEP_ONCE_SUBST_TAC (asl @ thl));
601
602
603
604
605(* ================================================================== *)
606(*                                                                    *)
607(* The tactics including LIST in their name take a list of lists of   *)
608(* implication theorems, and attempt to use each list of theorems     *)
609(* once, in order, left to right.  Each list of theorems is applied   *)
610(* by rewriting with each theorem in it as many times as they apply.  *)
611(* The hypotheses added in the process of dependent rewriting are     *)
612(* collected from all rewritings, but they are not rewritten by the   *)
613(* LIST tactics.  This gives a moderate and more controlled degree    *)
614(* of dependent rewriting than provided by DEP_REWRITE_TAC.           *)
615(*                                                                    *)
616(* ================================================================== *)
617
618
619
620fun DEP_LIST_FIND_THEN (ttac:thm->tactic) thss :tactic =
621    DEP_TAC
622         (EVERY_DEP (map (fn ths =>
623             REPEAT_DEP (CHANGED_DEP
624                (EVERY_DEP (map (fn th =>
625                                    APPLY_IMP_THEN ttac th
626                                    ORELSE_DEP TAC_DEP (ttac th))
627                                 (flatten (map CONJUNCTS ths))))))
628                          thss))
629    handle _ => failwith "DEP_LIST_FIND_THEN";
630
631
632
633val DEP_PURE_LIST_REWRITE_TAC :(thm list list)->tactic =
634    DEP_LIST_FIND_THEN (fn th => Ho_Rewrite.PURE_REWRITE_TAC[th]);
635
636val DEP_LIST_REWRITE_TAC :(thm list list)->tactic =
637    DEP_LIST_FIND_THEN (fn th => Ho_Rewrite.REWRITE_TAC[th]);
638
639fun DEP_PURE_LIST_ASM_REWRITE_TAC thss :tactic =
640    Tactical.ASSUM_LIST (fn asl => DEP_PURE_LIST_REWRITE_TAC
641                                   (map (fn ths => asl @ ths) thss));
642
643fun DEP_LIST_ASM_REWRITE_TAC thss :tactic =
644    Tactical.ASSUM_LIST (fn asl => DEP_LIST_REWRITE_TAC
645                                   (map (fn ths => asl @ ths) thss));
646
647
648
649
650(* ================================================================== *)
651(*                                                                    *)
652(* The tactics without ONCE attept to reuse all theorems until no     *)
653(* changes can be achieved in the goal.  Hypotheses are rewritten     *)
654(* and new ones generated from them, continuing until no further      *)
655(* progress is possible.                                              *)
656(*                                                                    *)
657(* ================================================================== *)
658
659
660fun DEP_FIND_THEN (ttac:thm->tactic) ths :tactic =
661    DEP_TAC (REPEAT_DEP (CHANGED_DEP
662         (EVERY_DEP (map (fn th => APPLY_IMP_THEN ttac th
663                                    ORELSE_DEP TAC_DEP (ttac th))
664                          (flatten (map CONJUNCTS ths))))))
665    handle _ => failwith "DEP_FIND_THEN";
666
667
668
669
670fun DEP_PURE_REWRITE_TAC thl :tactic =
671    REPEAT (CHANGED_TAC (DEP_FIND_THEN
672                           (fn th => Ho_Rewrite.PURE_REWRITE_TAC[th]) thl));
673
674fun DEP_REWRITE_TAC thl :tactic =
675    REPEAT (CHANGED_TAC (DEP_FIND_THEN
676                           (fn th => Ho_Rewrite.REWRITE_TAC[th]) thl));
677
678fun DEP_PURE_ASM_REWRITE_TAC thl :tactic =
679    Tactical.ASSUM_LIST (fn asl => DEP_PURE_REWRITE_TAC (asl @ thl));
680
681fun DEP_ASM_REWRITE_TAC thl :tactic =
682    Tactical.ASSUM_LIST (fn asl => DEP_REWRITE_TAC (asl @ thl));
683
684
685end
686
687(* ================================================================== *)
688(* ================================================================== *)
689(*                 END OF DEPENDENT REWRITING TACTICS                 *)
690(* ================================================================== *)
691(* ================================================================== *)
692
693
694end;
695
696
697
698(* TEST EXAMPLES:
699
700load "dep_rewrite";
701open dep_rewrite;
702show_rewrites := true;
703
704(* Example theorems to play with: *)
705
706open arithmeticTheory;
707
708(* Implication arithmetic theorems:
709
710val LESS_LESS_EQ_TRANS = |- !m n p. m < n /\ n <= p ==> m < p : thm
711val LESS_EQ_LESS_TRANS = |- !m n p. m <= n /\ n < p ==> m < p : thm
712val LESS_MULT2 = |- !m n. 0 < m /\ 0 < n ==> 0 < m * n : thm
713val CANCEL_SUB = |- !p n m. p <= n /\ p <= m ==> ((n - p = m - p) = n = m)
714  : thm
715val SUB_CANCEL = |- !p n m. n <= p /\ m <= p ==> ((p - n = p - m) = n = m)
716  : thm
717val SUB_LESS_EQ_ADD = |- !m p. m <= p ==> (!n. p - m <= n = p <= m + n) : thm
718val LESS_EQ_IMP_LESS_SUC = |- !n m. n <= m ==> n < SUC m : thm
719val LESS_IMP_LESS_ADD = |- !n m. n < m ==> (!p. n < m + p) : thm
720val SUB_SUB = |- !b c. c <= b ==> (!a. a - b - c = (a + c) - b) : thm
721val LESS_EQ_SUB_LESS = |- !a b. b <= a ==> (!c. a - b < c = a < b + c) : thm
722val LESS_EQ_ADD_SUB = |- !c b. c <= b ==> (!a. (a + b) - c = a + (b - c)) : thm
723val LESS_SUB_ADD_LESS = |- !n m i. i < n - m ==> i + m < n : thm
724val SUB_LESS_OR = |- !m n. n < m ==> n <= m - 1 : thm
725val INV_PRE_LESS_EQ = |- !n. 0 < n ==> (!m. PRE m <= PRE n = m <= n) : thm
726val INV_PRE_LESS = |- !m. 0 < m ==> (!n. PRE m < PRE n = m < n) : thm
727val MOD_MOD = |- !n. 0 < n ==> (!k. (k MOD n) MOD n = k MOD n) : thm
728val MOD_PLUS =
729  |- !n. 0 < n ==> (!j k. (j MOD n + k MOD n) MOD n = (j + k) MOD n) : thm
730val MOD_TIMES = |- !n. 0 < n ==> (!q r. (q * n + r) MOD n = r MOD n) : thm
731val MOD_MULT = |- !n r. r < n ==> (!q. (q * n + r) MOD n = r) : thm
732val ZERO_DIV = |- !n. 0 < n ==> (0 DIV n = 0) : thm
733val ZERO_MOD = |- !n. 0 < n ==> (0 MOD n = 0) : thm
734val MOD_EQ_0 = |- !n. 0 < n ==> (!k. (k * n) MOD n = 0) : thm
735val LESS_MOD = |- !n k. k < n ==> (k MOD n = k) : thm
736val DIV_MULT = |- !n r. r < n ==> (!q. (q * n + r) DIV n = q) : thm
737val MOD_UNIQUE = |- !n k r. (?q. (k = q * n + r) /\ r < n) ==> (k MOD n = r)
738  : thm
739val DIV_UNIQUE = |- !n k q. (?r. (k = q * n + r) /\ r < n) ==> (k DIV n = q)
740  : thm
741val DIV_LESS_EQ = |- !n. 0 < n ==> (!k. k DIV n <= k) : thm
742val LESS_EQUAL_ANTISYM = |- !n m. n <= m /\ m <= n ==> (n = m) : thm
743val LESS_MONO_MULT = |- !m n p. m <= n ==> m * p <= n * p : thm
744val LESS_IMP_LESS_OR_EQ = |- !m n. m < n ==> m <= n : thm
745val LESS_EQ_LESS_EQ_MONO = |- !m n p q. m <= p /\ n <= q ==> m + n <= p + q
746  : thm
747val LESS_EQ_TRANS = |- !m n p. m <= n /\ n <= p ==> m <= p : thm
748val LESS_MONO_ADD = |- !m n p. m < n ==> m + p < n + p : thm
749val ADD_EQ_SUB = |- !m n p. n <= p ==> ((m + n = p) = m = p - n) : thm
750val LESS_SUC_NOT = |- !m n. m < n ==> ~(n < SUC m) : thm
751val INV_PRE_EQ = |- !m n. 0 < m /\ 0 < n ==> ((PRE m = PRE n) = m = n) : thm
752val PRE_SUC_EQ = |- !m n. 0 < n ==> ((m = PRE n) = SUC m = n) : thm
753val SUB_ADD = |- !m n. n <= m ==> ((m - n) + n = m) : thm
754val LESS_ADD_NONZERO = |- !m n. ~(n = 0) ==> m < m + n : thm
755val ADD_INV_0 = |- !m n. (m + n = m) ==> (n = 0) : thm
756val LESS_CASES_IMP = |- !m n. ~(m < n) /\ ~(m = n) ==> n < m : thm
757val LESS_NOT_SUC = |- !m n. m < n /\ ~(n = SUC m) ==> SUC m < n : thm
758val LESS_SUC_EQ_COR = |- !m n. m < n /\ ~(SUC m = n) ==> SUC m < n : thm
759val OR_LESS = |- !m n. SUC m <= n ==> m < n : thm
760val LESS_OR = |- !m n. m < n ==> SUC m <= n : thm
761val FUN_EQ_LEMMA = |- !f x1 x2. f x1 /\ ~(f x2) ==> ~(x1 = x2) : thm
762val LESS_TRANS = |- !m n p. m < n /\ n < p ==> m < p : thm
763val LESS_MONO_REV = |- !m n. SUC m < SUC n ==> m < n : thm
764
765*)
766
767(*
768[LESS_EQ_ADD_SUB,SUB_ADD,SUB_SUB,ADD_EQ_SUB,LESS_TRANS,SUB_LESS_EQ_ADD,
769 CANCEL_SUB,LESS_EQ_SUB_LESS,LESS_EQ_LESS_EQ_MONO];
770*)
771
772
773g `(10 + y) - y < 12`;
774e(DEP_ONCE_REWRITE_TAC[LESS_EQ_ADD_SUB]);
775e(RW_TAC arith_ss []);
776drop();
777
778g `(x + y) - (x + 2) <= 2 * y`;
779e(ASM_CASES_TAC (--`2 <= y`--));
780
781 e(DEP_REWRITE_TAC[SUB_LESS_EQ_ADD,LESS_EQ_LESS_EQ_MONO]);
782 e(RW_TAC arith_ss []);
783
784 val SUB_EQ_0_IMP = GEN_ALL(snd(EQ_IMP_RULE (SPEC_ALL SUB_EQ_0)));
785 e(DEP_REWRITE_TAC[SUB_EQ_0_IMP]);
786 e(RW_TAC arith_ss []);
787
788drop();
789
790g `(1 + (2 + (3 + (4 + (5 + 6))))) - 5 = 16`;
791e(DEP_REWRITE_TAC[LESS_EQ_ADD_SUB]);
792e(RW_TAC arith_ss []);
793drop();
794
795g `EL (SUC(SUC 0)) (ZIP([1;2;3],ZIP([4;5;6],[7;8;9]))) = (3,6,9)`;
796val EL_ZIP = listTheory.EL_ZIP;
797e(DEP_REWRITE_TAC[EL_ZIP]);
798e(RW_TAC list_ss []);
799drop();
800
801g `0 < (@n. 0 < n)`;
802e(DEP_ONCE_REWRITE_TAC[SELECT_AX]);
803drop();
804
805g `!P f x. P f ==> (x = f x)`;
806e(DEP_ONCE_REWRITE_TAC[RIGHT_FORALL_IMP_THM]);
807drop();
808
809*)
810