1(* 2quietdec := true; 3loadPath := 4 (concat [Globals.HOLDIR, "/src/quantHeuristics"]) :: 5 !loadPath; 6*) 7 8 9open HolKernel Parse boolLib Drule ConseqConv computeLib 10open optionTheory 11open quantHeuristicsLib; 12 13(* 14quietdec := false; 15*) 16 17 18(*Simple find an equation and instatiate it, 19 same as UNWIND_CONV*) 20 21val t = ``?x. Q /\ (x=7) /\ P x``; 22val t = ``!x. ((x=7) /\ Q) ==> P x``; 23 24(* Result: Q /\ P 7 *) 25val thm = SIMP_CONV std_ss [] t; 26val thm = QUANT_INSTANTIATE_CONV [] t; 27val thm = QUANT_INSTANTIATE_CONV []``?x. x = 2``; 28 29(*Quantifiers are resorted to be able to find easy instantations*) 30val t = ``?y x z. (x=y+z) /\ X x y z``; 31val t = ``!y x z. ~(x=y+z) \/ X x y z``; 32 33val thm = SIMP_CONV std_ss [] t 34val thm = QUANT_INSTANTIATE_CONV [] t 35 36 37(*However, the new library can handle more difficult nestings than 38 the existing UNWIND conversions*) 39 40val t = ``?x. ((x=7) \/ (7 = x)) /\ P x``; 41(* Result: P 7 *) 42 43val t = ``?x. !y. (x=7) /\ P x y``; 44(* Result: !y. P 7 y *) 45 46val t = ``?x. (!z. Q z /\ (x=7)) /\ P x`` 47(* Result: (!z. Q z) /\ P 7 /\ Q t *) 48 49val t = ``!x z. ?g. (((x=7) /\ Q g)) ==> P x`` 50(* Result: (?g. Q g) ==> P 7 *) 51 52val thm = QUANT_INSTANTIATE_CONV [] t 53val thm = SIMP_CONV std_ss [] t 54 55 56(* 57If one want's to know in detail, how it comes up with a guess some 58verbose output is available*) 59 60(*no debug*) 61set_trace "QUANT_INSTANTIATE_HEURISTIC" 0; 62 63(*simple traces*) 64set_trace "QUANT_INSTANTIATE_HEURISTIC" 1; 65 66(*show theorems in guesses*) 67set_trace "QUANT_INSTANTIATE_HEURISTIC" 2; 68set_trace "QUANT_INSTANTIATE_HEURISTIC___print_term_length" 2000; 69 70val thm = QUANT_INSTANTIATE_CONV [] t; 71 72set_trace "QUANT_INSTANTIATE_HEURISTIC" 0; 73 74 75 76 77(*Instead of just looking for an instantiation i such that all other values 78 v != i the predicate P i holds (for allquantfication) or does not hold (for 79 existential quantification), the new library also looks for values that satisfy / 80 dissatisfy the predicate*) 81 82 83(*figures out to instantiate x with 8*) 84val t = ``!x. P /\ ~(8 = x) /\ Z``; 85val thm = QUANT_INSTANTIATE_CONV [] t 86 87 88(*figures out to instantiate x with 8*) 89val t = ``?x. P \/ (8 = x) \/ Z``; 90val thm = QUANT_INSTANTIATE_CONV [] t 91 92 93 94(*The new library also uses unification to figure out instantions*) 95val t = ``?x. (f(8 + 2) = f(x + 2)) /\ P(10)``; 96val t = ``?x. (f(8 + 2) = f(x + 2)) /\ P(f (x + 2))``; 97val t = ``?x. (f(8 + 2) = f(x + 2)) /\ P(f (2 + x))``; (*fails *) 98 99val t = ``?x. P \/ (f(8 + 2) = f(x + 2)) \/ Z``; 100val t = ``?x. P /\ (f(8 + 2) = f(x + 2)) /\ 101 g (f (x+2)) /\ Z``; 102 103val t = ``?x. P /\ (f 2 = f x) /\ Q /\ Q2(f x) /\ Z /\ 104 (f x = f 2)``; 105 106val thm = QUANT_INSTANTIATE_CONV [] t 107val thm = SIMP_CONV std_ss [] t 108 109 110 111(*Bound variables in instantiations can be tackeled. 112 More convincing examples for having free variables in 113 guesses will follow later when datatype specific code is used.*) 114 115val t = ``?x. P /\ (!y. x = y + 2) /\ Z x``; 116val thm = QUANT_INSTANTIATE_CONV [] t; 117(*result ?y'. P /\ (!y. y' + 2 = y + 2) /\ Z (y' + 2)*) 118 119 120 121val t = ``?x. P /\ (?y. x = y + 2) /\ Z x``; 122(*matching + bound variables 123 result ?y'. P /\ Z (y' + 2)*) 124 125val thm = QUANT_INSTANTIATE_CONV [] t 126 127 128 129(*There is a little bit of support for unique existential quantification, 130 however, neither bound variables nor matching can be used for it*) 131val t = ``?!x. !z. ((7=x) /\ Q z x)``; 132val thm = QUANT_INSTANTIATE_CONV [] t 133 134 135(* By default QUANT_INSTANTIATE_CONV just knows about 136 boolean operators and equations. On easy way to 137 extend this is using TypeBase. 138 In the following examples, TypeBase is used to come up with guesses*) 139 140val t = ``!x. ~(x = 0) ==> P x`` 141(*Result !x_n. P (SUC x_n) *) 142 143val thm = QUANT_INSTANTIATE_CONV [TypeBase_qp] t 144 145 146(*To come up with this result, the case-theorem form TypeBase has been 147 used. It states that if an number is not zero, it's the successor of 148 something*) 149 150val t = ``!x. (x = 0)`` 151(*Result F, distinct theorem of TypeBase used*) 152val thm = QUANT_INSTANTIATE_CONV [TypeBase_qp] t 153 154 155val t = ``?x. ((x,y) = (0,z)) /\ (P x)`` 156(*Result ((0,y) = (0,z)) /\ P 0, one_one theorem of TypeBase used*) 157 158val thm = QUANT_INSTANTIATE_CONV [TypeBase_qp] t 159 160(* The new library supports guesses without justification. For example, 161 there is support for just considering the conclusion of an implication. *) 162 163val t = ``?x. P x ==> ((x = 2) /\ Q x)`` 164 165(* in general x cannot be instantiated, because nothing is know about P and Q. 166 (x = 2) looks tempting, but in case ~(Q 2), P 2 and ~(P 3) this is wrong. *) 167 168val thm = QUANT_INSTANTIATE_CONV [] t (* fails *) 169val thm = QUANT_INSTANTIATE_CONV [implication_concl_qp] t (* fails with unjustified guesses *) 170 171(* We can't prove equality, but just implications using a heuristic that produces 172 unjustified guesses *) 173val thm = QUANT_INSTANTIATE_CONSEQ_CONV [implication_concl_qp] CONSEQ_CONV_STRENGTHEN_direction t 174 175(* Expanding is possible as well *) 176val thm = EXPAND_QUANT_INSTANTIATE_CONV [implication_concl_qp] t 177val thm = SIMP_CONV (std_ss ++ EXPAND_QUANT_INST_ss [implication_concl_qp]) [] t 178 179 180 181(*The main advantage of the new library is however, it is user extensible. 182 TypeBase_qp uses some theorem from TypeBase. Users can provide there own parameters. 183 In the following some examples are given, how these parameters can be used. 184*) 185 186 187 188val t = ``?x y z. (x = 1) /\ (y = 2) /\ (z = 3)`` 189(*Standard calls eliminate all 3 variables 190 |- ?x y z. (x = 1) /\ (y = 2) /\ (z = 3) = T 191*) 192val thm = QUANT_INSTANTIATE_CONV [] t 193 194 195(* filter_qp gets a list of ML functions "filter v t" that get a variable v and a term t and 196 return whether the tool should try to instantiate v in t. For example, 197 let's just get rid of y by using filter_qp 198 199 |- ?x y z. (x = 1) /\ (y = 2) /\ (z = 3) = 200 ?x z. (x = 1) /\ (z = 3)*) 201 202val thm = QUANT_INSTANTIATE_CONV [filter_qp [fn v => fn t => (v = ``y:num``)]] t 203 204 205(* By default, the quantifier heuristics don't know IS_SOME. *) 206val t = ``!x. IS_SOME x ==> P x`` 207val thm = QUANT_INSTANTIATE_CONV [] t (* fails *) 208 209(* By adding a rewrite rule for IS_SOME, the standard rules for equations and 210 quantifiers can be exploited *) 211val IS_SOME_EXISTS = prove (``IS_SOME x = (?x'. x = SOME x')``, Cases_on `x` THEN SIMP_TAC std_ss []); 212val thm = QUANT_INSTANTIATE_CONV [rewrite_qp[IS_SOME_EXISTS]] t 213 214(* |- (!x. IS_SOME x ==> P x) <=> !x'. IS_SOME (SOME x') ==> P (SOME x') 215 216 To clean up the result after instantiation, rewrite theorems can be provided via 217 final_rewrite_qp 218*) 219 220val thm = QUANT_INSTANTIATE_CONV [rewrite_qp[IS_SOME_EXISTS], final_rewrite_qp[option_CLAUSES]] t 221 222(* 223 val thm = 224 |- (!x. IS_SOME x ==> P x) <=> !x'. P (SOME x'): 225 thm 226 227if rewrites are not enough, conv_ss can be used as well. 228*) 229 230 231(* sometimes you want to apply knowledge that some predicate is true or false. 232 instantiation_qp provides an interface for giving explicit theorems to state 233 satisfying and dissatisfying instantiations. *) 234 235val t = ``?m:num. n <= m`` 236 237(* By default, this can't be handled, but adding the reflexivity theorem helps *) 238 239val thm = QUANT_INSTANTIATE_CONV [] t (* fails *) 240val thm = QUANT_INSTANTIATE_CONV [instantiation_qp[arithmeticTheory.LESS_EQ_REFL]] t (* succeeds *) 241 242 243(* Let's consider an example to demonstrate context *) 244val t = ``P m ==> ?n. P n`` 245 246(* applied naively, the tool fails *) 247 248val thm = QUANT_INSTANTIATE_CONV [] t (* fail *) 249 250(* This is not surprising, because the conversion does not collect context. 251 The simplifier has to be used to collect context *) 252val thm = SIMP_CONV (bool_ss++QUANT_INST_ss []) [] t 253 254(* Another option is using consequence conversions. However, this will create only implications. 255 256 |- T ==> P m ==> ?n. P n: 257*) 258 259val thm = QUANT_INSTANTIATE_CONSEQ_CONV [] CONSEQ_CONV_STRENGTHEN_direction t (* fail *) 260 261(* 262Lets for example teach the heuristic to 263find counterexamples for natural numbers. 264 265Thanks to the dictinct-theorem from TypeBase, it is already possible, 266to find counterexamples for theorems of the form ``0`` and ``SUC n`` 267*) 268 269val t = ``!x. x = 0`` 270val t = ``?x. ~(x = SUC n)`` 271val t = ``?x. ((x = SUC n) /\ Q x n) ==> P x`` 272 273val thm = QUANT_INSTANTIATE_CONV [TypeBase_qp] t 274 275 276(*However, for arbitrary numbers that is not possible yet 277 (hopefully, perhaps it got added meanwhile). At least 278 the theorems from TypeBase are not sufficient. One needs 279 a stronger one. *) 280 281val t = ``?x:num. ((x = n) /\ Q x n) ==> P x`` 282 283(*the normal one raises UNCHANGED*) 284val thm = QUANT_INSTANTIATE_CONV [TypeBase_qp] t 285val thm = QUANT_INSTANTIATE_CONV [] t 286 287(*The extended one is able to reduce it to true, by knowing that ~(SUC n = n) holds*) 288val thm = QUANT_INSTANTIATE_CONV [distinct_qp [prim_recTheory.SUC_ID]] t 289 290(*One can also use a ready qp*) 291val thm = QUANT_INSTANTIATE_CONV [num_qp] t 292 293 294 295(* There is no info about predicate sets in TypeBase. However 296 a case distinction might by usefull*) 297 298val SIMPLE_SET_CASES = prove ( 299``!s. (s = {}) \/ ?x t. (s = x INSERT t)``, 300PROVE_TAC[pred_setTheory.SET_CASES]); 301 302 303val t = ``!s. ~(s = {}) ==> (CARD s > 0)``; 304 305(*raises unchanged*) 306val thm = QUANT_INSTANTIATE_CONV [] t; 307 308(*The extended one is able to reduce it*) 309val thm = QUANT_INSTANTIATE_CONV 310 [cases_qp [SIMPLE_SET_CASES]] t 311 312 313 314 315(* 316 There is no mentioning of IS_SOME in TypeBase. However, being able 317 to find instantiations would be great. A simple way to achive it via 318 repacing IS_SOME x with (?x'. x = SOME x') during the heuristic search. 319*) 320 321 322val t = ``!x. IS_SOME x ==> P x``; 323 324(*raises unchanged*) 325val thm = QUANT_INSTANTIATE_CONV [] t; 326 327 328val IS_SOME_EXPAND = prove (``IS_SOME x = ?x'. x = SOME x'``, 329 Cases_on `x` THEN SIMP_TAC std_ss []); 330 331val thm = QUANT_INSTANTIATE_CONV [rewrite_qp [IS_SOME_EXPAND]] t; 332 333 334(*The same works if we use a conversion instead*) 335val thm = QUANT_INSTANTIATE_CONV 336 [convs_qp [REWR_CONV IS_SOME_EXPAND]] t; 337 338 339(*notice that here REWR_CONV is used, so the rewrite takes just place at 340 top-level. This is what happens internally, 341 if IS_SOME_EXPAND is added to the list of 342 REWRITES. Other conversions like e.g. REWRITE_CONV would work as well, 343 but for REWRITE_CONV IS_SOME would be replaced at subpositions. Thus, there would 344 be an exponential blowup!!! Have a look at the debug output 345 to compare*) 346 347set_trace "QUANT_INSTANTIATE_HEURISTIC" 1; 348val thm = QUANT_INSTANTIATE_CONV 349 [convs_qp [REWR_CONV IS_SOME_EXPAND]] t; 350 351val thm = QUANT_INSTANTIATE_CONV 352 [convs_qp [REWRITE_CONV [IS_SOME_EXPAND]]] t; 353 354(*TOP_ONCE_REWRITE_CONV is suitable as well, 355 it behaves like REWR_CONV for a list of theorems*) 356 357val thm = QUANT_INSTANTIATE_CONV 358 [convs_qp [TOP_ONCE_REWRITE_CONV [IS_SOME_EXPAND]]] t; 359 360 361set_trace "QUANT_INSTANTIATE_HEURISTIC" 0; 362 363fun dummy_heuristic sys v t = 364let 365 val i = mk_var ("choose_me", type_of v); 366in 367 guess_list2collection ([], [guess_general (i,[])]) 368end; 369 370val dummy_qp = top_heuristics_qp [dummy_heuristic] 371 372(* Alternative way: *) 373 374val dummy_qp = oracle_qp (fn v => fn t => 375 let 376 val i = mk_var ("choose_me", type_of v); 377 in 378 SOME (i, []) 379 end) 380 381 382val t = ``?x. P x``; 383 384(* Nothing can be proved, we only say: "Trust me". Therefore the normal conversion fails. *) 385val thm = QUANT_INSTANTIATE_CONV [dummy_qp] t 386 387(* Consequence Conversions and expanding conversions are fine though *) 388val thm = QUANT_INSTANTIATE_CONSEQ_CONV [dummy_qp] CONSEQ_CONV_STRENGTHEN_direction t 389 390(*result 391 val thm = |- P choose_me ==> (?x. P x) : thm 392*) 393 394val thm = EXPAND_QUANT_INSTANTIATE_CONV [dummy_qp] t 395 396(*result 397 val thm = |- (?x. P x) <=> (!x. ~(x = choose_me) ==> ~P x) ==> P choose_me : 398 thm 399*) 400 401 402(* Let's write a slightly more interesting oracle that 403 instantiates every list with a non-empty one *) 404 405(* 406 407val t = ``P (TL (l:'a list))`` 408val v = ``l:'a list`` 409*) 410val dummy_list_qp = oracle_qp (fn v => fn t => 411 let 412 val (v_name, v_list_ty) = dest_var v; 413 val v_ty = listSyntax.dest_list_type v_list_ty; 414 415 val x = mk_var (v_name ^ "_hd", v_ty); 416 val xs = mk_var (v_name ^ "_tl", v_list_ty); 417 val x_xs = listSyntax.mk_cons (x, xs) 418 in 419 SOME (x_xs, [x, xs]) 420 end) 421 422val t = ``?x:'a list y:'b. P (x, y)`` 423 424(* Be careful to use a tactic that does no REDEPTH but just depth, because otherwise 425 the procedure will not terminate. *) 426val thm = NORE_QUANT_INSTANTIATE_CONSEQ_CONV [dummy_list_qp] CONSEQ_CONV_STRENGTHEN_direction t 427 428 429(*There is a stateful argument stateful_qp, 430 let's add something to it*) 431 432val _ = clear_stateful_qp (); 433val _ = stateful_qp___add_combine_arguments 434 [distinct_qp [prim_recTheory.SUC_ID], 435 rewrite_qp [arithmeticTheory.EQ_ADD_RCANCEL, 436 arithmeticTheory.EQ_ADD_LCANCEL, 437 arithmeticTheory.ADD_CLAUSES]]; 438 439 440 441 442 443(* Some examples on how QUANT_INSTANTIATE_CONV behaves 444 on standard datatypes. Here both the statefull as well 445 as specific arguments for each datatype are used.*) 446 447 448(* There is basic support for numbers. Just very simple stuff. *) 449 450val t = ``!y:num. x = y`` 451val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t; 452val thm = QUANT_INSTANTIATE_CONV [num_qp] t; 453 454val t = ``!x. (SUC x = SUC 3) ==> P x`` 455val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t; 456val thm = QUANT_INSTANTIATE_CONV [num_qp] t; 457 458 459val t = ``!x. (x + z = 3 + z) ==> P x`` 460val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t; 461val thm = QUANT_INSTANTIATE_CONV [num_qp] t; 462 463 464val t = ``!x. P x /\ ~(x = 0) ==> Q x z`` 465val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t; 466val thm = QUANT_INSTANTIATE_CONV [num_qp] t; 467 468 469 470 471(* Pairs *) 472 473val t = ``!p. (x = FST p) ==> Q p`` 474val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t; 475 476val t = ``!p. ?t. ((f t = FST p) /\ Z x) ==> Q p`` 477val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 478 479val t = ``?p. ((SND p) = 7) /\ Q p`` 480val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 481 482val t = ``?v. (v,X) = Z`` 483val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 484 485val t = ``?v. (v,X) = (a,9)`` 486val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 487 488val t = ``?v. (\ (pa, pb, pc). P pa pb pc) v`` 489val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 490 491val t = ``?v. (\ ((pa, pb), pc). P pa pb pc) v`` 492val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 493 494 495(*customising pair_qp*) 496val t = ``?p:('a # ('b # 'c # 'd) # 'a). P (FST p) (SND p) /\ Q p`` 497 498val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t 499val thm = QUANT_INSTANTIATE_CONV [pair_qp [split_pair___FST_SND___pred true]] t 500val thm = QUANT_INSTANTIATE_CONV [pair_qp [split_pair___FST_SND___pred false]] t 501 502 503val t = ``?p:('a # ('b # 'c # 'd) # 'a). P p`` 504 505val thm = QUANT_INSTANTIATE_CONV [pair_default_qp] t (*raises unchanged*) 506val thm = QUANT_INSTANTIATE_CONV [pair_qp [split_pair___ALL___pred]] t 507 508 509(*Some things about option types*) 510val t = ``!x. IS_SOME x`` 511val thm = QUANT_INSTANTIATE_CONV [std_qp] t 512 513val t = ``!x. IS_NONE x`` 514val thm = QUANT_INSTANTIATE_CONV [std_qp] t 515 516val t = ``!x. IS_SOME x ==> P x``; 517val thm = QUANT_INSTANTIATE_CONV [std_qp] t 518 519val t = ``!x. IS_NONE x \/ P x`` 520val thm = QUANT_INSTANTIATE_CONV [option_qp] t 521 522val t = ``!x. IS_SOME x \/ P x`` 523val thm = QUANT_INSTANTIATE_CONV [std_qp] t 524 525val t = ``!x. (x = SOME y) /\ P x`` 526val thm = QUANT_INSTANTIATE_CONV [std_qp] t 527 528 529 530(*Some things about lists, 531 Typebase contains enough for these simple examples*) 532val t = ``!l. (~(l = []) ==> (LENGTH l > 0))``; 533val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t 534val thm = QUANT_INSTANTIATE_CONV [list_qp] t 535val thm = QUANT_INSTANTIATE_CONV [std_qp] t 536 537val t = ``!l. (l = h::h2) \/ X`` 538val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t 539val thm = QUANT_INSTANTIATE_CONV [list_qp] t 540 541val t = ``!l. (l = h::h2)`` 542val thm = QUANT_INSTANTIATE_CONV [stateful_qp] t 543val thm = QUANT_INSTANTIATE_CONV [list_qp] t 544 545val t = ``!l. (NULL l)`` 546val thm = QUANT_INSTANTIATE_CONV [list_qp] t 547 548 549val t = ``!l. NULL l ==> P l`` 550val thm = QUANT_INSTANTIATE_CONV [list_qp] t 551 552val t = ``!l. ~(NULL l) ==> P l`` 553val thm = QUANT_INSTANTIATE_CONV [list_qp] t 554 555 556 557(*Some things about records and the simplfier*) 558 559Hol_datatype `my_record = <| field1 : bool ; 560 field2 : num ; 561 field3 : bool |>` 562 563(*using the default record_qp. It does not simplify, and applies to everything*) 564val t = ``?r1:my_record. r1.field1`` 565val thm = QUANT_INSTANTIATE_CONV [record_default_qp] t 566 567(*turning simplification on*) 568val t = ``?r1:my_record. r1.field1`` 569val thm = QUANT_INSTANTIATE_CONV [record_qp true (K (K true))] t; 570 571(*using it as a ssfrag*) 572val t = ``?r1:my_record. r1.field1`` 573val thm = SIMP_CONV (std_ss ++ QUANT_INST_ss [record_qp true (K (K true))]) [] t; 574val thm = SIMP_CONV (std_ss ++ QUANT_INST_ss [record_default_qp]) [] t; 575 576set_goal ([], ``?r1:my_record. r1.field1``); 577e (SRW_TAC [QUANT_INST_ss [record_default_qp]] []) 578 579 580 581(*Tactics using the assumption*) 582 583set_goal ([], ``!x. IS_SOME x ==> P x``); 584 585set_goal ([], ``!x y. IS_SOME x /\ IS_SOME y ==> (x = y)``); 586 587e ( 588 REPEAT STRIP_TAC THEN 589 ASM_QUANT_INSTANTIATE_TAC [std_qp] 590) 591 592(* in contrast, the simplifier does not work, since it does not instantiate free variables *) 593e ( 594 REPEAT STRIP_TAC THEN 595 FULL_SIMP_TAC (std_ss++(QUANT_INST_ss [std_qp])) [] 596) 597 598 599 600(*A combination of quantHeuristics with consequence Conversions 601 leads to an extended version of EXISTS_TAC. This version 602 can instantiate quantifiers that occur as subterms. As a result, 603 existential quantifiers can be instantiated, if they occur under even 604 negation level and universal ones under odd. Moreover, it is possible 605 to keep free variables in the instantiations.*) 606 607val t = ``!x:num. (!z:num. P x z) ==> ?a:num b:num. Q a b z``; 608set_goal ([], t) 609(*Result ``!x . ( P x 0) ==> ? b a'. Q (SUC a') b z``*) 610 611 612e (QUANT_INST_TAC [("z", `0`, []), 613 ("a", `SUC a'`, [`a'`])]); 614 615 616``(?x:num. P x) /\ (?x. x \/ y)`` 617 618(* Let's play around with conjunctions and guessing *) 619val t = ``P 2 ==> ?x. P x /\ Q x`` 620 621(* in general x cannot be instantiated, because nothing is know about P and Q. 622 (x = 2) looks tempting, but in case ~(Q 2), P 3 and Q 3 this is wrong. *) 623 624val thm = QUANT_INSTANTIATE_CONV [] t (* fails *) 625val thm = QUANT_INSTANTIATE_CONV [conj_lift_qp] t (* fails with unjustified guesses *) 626 627(* We can't prove equality, but just implications using a heuristic that produces 628 unjustified guesses *) 629val thm = QUANT_INSTANTIATE_CONSEQ_CONV [conj_lift_qp] CONSEQ_CONV_STRENGTHEN_direction t 630 631(* Expanding is possible as well *) 632val thm = SIMP_CONV (std_ss ++ EXPAND_QUANT_INST_ss [conj_lift_qp]) [] t 633 634(* try it as a tactic *) 635set_goal ([], t) 636e (REPEAT STRIP_TAC) 637 638e (QUANT_INSTANTIATE_CONSEQ_TAC [conj_lift_qp]) 639 640(* or expand *) 641e (ASM_SIMP_TAC (std_ss ++ EXPAND_QUANT_INST_ss [conj_lift_qp]) []) 642