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