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