63 When constructing them, the variables @{text "zs"} need to be chosen so that |
69 When constructing them, the variables @{text "zs"} need to be chosen so that |
64 they do not occur in the @{text orules} and also be distinct from the @{text |
70 they do not occur in the @{text orules} and also be distinct from the @{text |
65 "preds"}. |
71 "preds"}. |
66 |
72 |
67 |
73 |
68 The first function constructs the term for one particular predicate (the |
74 The first function, named @{text defn_aux}, constructs the term for one |
69 argument @{text "pred"} in the code belo). The number of arguments of this predicate is |
75 particular predicate (the argument @{text "pred"} in the code below). The |
70 determined by the number of argument types given in @{text "arg_tys"}. |
76 number of arguments of this predicate is determined by the number of |
71 The other arguments are all the @{text "preds"} and the @{text "orules"}. |
77 argument types given in @{text "arg_tys"}. The other arguments of the |
|
78 function are the @{text orules} and all the @{text "preds"}. |
72 *} |
79 *} |
73 |
80 |
74 ML %linenosgray{*fun defn_aux lthy orules preds (pred, arg_tys) = |
81 ML %linenosgray{*fun defn_aux lthy orules preds (pred, arg_tys) = |
75 let |
82 let |
76 fun mk_all x P = HOLogic.all_const (fastype_of x) $ lambda x P |
83 fun mk_all x P = HOLogic.all_const (fastype_of x) $ lambda x P |
86 |> fold_rev mk_all preds |
93 |> fold_rev mk_all preds |
87 |> fold_rev lambda fresh_args |
94 |> fold_rev lambda fresh_args |
88 end*} |
95 end*} |
89 |
96 |
90 text {* |
97 text {* |
91 The function in Line 3 is just a helper function for constructing universal |
98 The function @{text mk_all} in Line 3 is just a helper function for constructing |
92 quantifications. The code in Lines 5 to 9 produces the fresh @{text |
99 universal quantifications. The code in Lines 5 to 9 produces the fresh @{text |
93 "zs"}. For this it pairs every argument type with the string |
100 "zs"}. For this it pairs every argument type with the string |
94 @{text [quotes] "z"} (Line 7); then generates variants for all these strings |
101 @{text [quotes] "z"} (Line 7); then generates variants for all these strings |
95 so that they are unique w.r.t.~to the predicates and @{text "orules"} (Line 8); |
102 so that they are unique w.r.t.~to the predicates and @{text "orules"} (Line 8); |
96 in Line 9 it generates the corresponding variable terms for the unique |
103 in Line 9 it generates the corresponding variable terms for the unique |
97 strings. |
104 strings. |
98 |
105 |
99 The unique free variables are applied to the predicate (Line 11) using the |
106 The unique variables are applied to the predicate in Line 11 using the |
100 function @{ML list_comb}; then the @{text orules} are prefixed (Line 12); in |
107 function @{ML list_comb}; then the @{text orules} are prefixed (Line 12); in |
101 Line 13 we quantify over all predicates; and in line 14 we just abstract |
108 Line 13 we quantify over all predicates; and in line 14 we just abstract |
102 over all the @{text "zs"}, i.e., the fresh arguments of the |
109 over all the @{text "zs"}, i.e., the fresh arguments of the |
103 predicate. A testcase for this function is |
110 predicate. A testcase for this function is |
104 *} |
111 *} |
105 |
112 |
106 local_setup %gray{* fn lthy => |
113 local_setup %gray{* fn lthy => |
107 let |
114 let |
108 val pred = @{term "even::nat\<Rightarrow>bool"} |
115 val def = defn_aux lthy eo_orules eo_preds (e_pred, e_arg_tys) |
109 val arg_tys = [@{typ "nat"}] |
|
110 val def = defn_aux lthy eo_orules eo_preds (pred, arg_tys) |
|
111 in |
116 in |
112 warning (Syntax.string_of_term lthy def); lthy |
117 warning (Syntax.string_of_term lthy def); lthy |
113 end *} |
118 end *} |
114 |
119 |
115 text {* |
120 text {* |
116 The testcase calls @{ML defn_aux} for the predicate @{text "even"} and prints |
121 where we use the shorthands defined in Figure~\ref{fig:shorthands}. |
|
122 The testcase calls @{ML defn_aux} for the predicate @{text "even"} and prints |
117 out the generated definition. So we obtain as printout |
123 out the generated definition. So we obtain as printout |
118 |
124 |
119 @{text [display] |
125 @{text [display] |
120 "\<lambda>z. \<forall>even odd. (even 0) \<longrightarrow> (\<forall>n. odd n \<longrightarrow> even (Suc n)) |
126 "\<lambda>z. \<forall>even odd. (even 0) \<longrightarrow> (\<forall>n. odd n \<longrightarrow> even (Suc n)) |
121 \<longrightarrow> (\<forall>n. even n \<longrightarrow> odd (Suc n)) \<longrightarrow> even z"} |
127 \<longrightarrow> (\<forall>n. even n \<longrightarrow> odd (Suc n)) \<longrightarrow> even z"} |
122 |
128 |
123 If we try out the function for the definition of freshness |
129 If we try out the function with the rules for freshness |
124 *} |
130 *} |
125 |
131 |
126 local_setup %gray{* fn lthy => |
132 local_setup %gray{* fn lthy => |
127 (warning (Syntax.string_of_term lthy |
133 (warning (Syntax.string_of_term lthy |
128 (defn_aux lthy fresh_orules [fresh_pred] (fresh_pred, fresh_arg_tys))); |
134 (defn_aux lthy fresh_orules [fresh_pred] (fresh_pred, fresh_arg_tys))); |
136 (\<forall>a s t. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
142 (\<forall>a s t. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
137 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
143 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
138 (\<forall>a b t. \<not> a = b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh z za"} |
144 (\<forall>a b t. \<not> a = b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh z za"} |
139 |
145 |
140 |
146 |
141 The second function for the definitions has to just iterate the function |
147 The second function, named @{text defns}, has to just iterate the function |
142 @{ML defn_aux} over all predicates. The argument @{text "preds"} is again |
148 @{ML defn_aux} over all predicates. The argument @{text "preds"} is again |
143 the the list of predicates as @{ML_type term}s; the argument @{text |
149 the the list of predicates as @{ML_type term}s; the argument @{text |
144 "prednames"} is the list of names of the predicates; @{text syns} are the |
150 "prednames"} is the list of binding names of the predicates; @{text syns} |
145 syntax annotations for each predicate; @{text "arg_tyss"} is |
151 are the list of syntax annotations for the predicates; @{text "arg_tyss"} is |
146 the list of argument-type-lists for each predicate. |
152 the list of argument-type-lists. |
147 *} |
153 *} |
148 |
154 |
149 ML %linenosgray{*fun defns rules preds prednames syns arg_typss lthy = |
155 ML %linenosgray{*fun defns rules preds prednames syns arg_typss lthy = |
150 let |
156 let |
151 val thy = ProofContext.theory_of lthy |
157 val thy = ProofContext.theory_of lthy |
228 Drule.instantiate' [SOME (ctyp_of_term ctrm)] [NONE, SOME ctrm] @{thm spec}*} |
234 Drule.instantiate' [SOME (ctyp_of_term ctrm)] [NONE, SOME ctrm] @{thm spec}*} |
229 |
235 |
230 text {* |
236 text {* |
231 This helper function instantiates the @{text "?x"} in the theorem |
237 This helper function instantiates the @{text "?x"} in the theorem |
232 @{thm spec} with a given @{ML_type cterm}. We call this helper function |
238 @{thm spec} with a given @{ML_type cterm}. We call this helper function |
233 in the tactic: |
239 in the next tactic, called @{text inst_spec_tac}. |
234 *} |
240 *} |
235 |
241 |
236 ML{*fun inst_spec_tac ctrms = |
242 ML{*fun inst_spec_tac ctrms = |
237 EVERY' (map (dtac o inst_spec) ctrms)*} |
243 EVERY' (map (dtac o inst_spec) ctrms)*} |
238 |
244 |
239 text {* |
245 text {* |
240 This tactic allows us to instantiate in the following proof the |
246 This tactic expects a list of @{ML_type cterm}s. It allows us in the following |
241 three quantifiers in the assumption. |
247 proof to instantiate the three quantifiers in the assumption. |
242 *} |
248 *} |
243 |
249 |
244 lemma |
250 lemma |
245 fixes P::"nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" |
251 fixes P::"nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" |
246 shows "\<forall>x y z. P x y z \<Longrightarrow> True" |
252 shows "\<forall>x y z. P x y z \<Longrightarrow> True" |
286 shows "(\<And>a b. a \<noteq> b \<Longrightarrow> P a (Var b)) \<Longrightarrow> |
292 shows "(\<And>a b. a \<noteq> b \<Longrightarrow> P a (Var b)) \<Longrightarrow> |
287 (\<And>a t s. \<lbrakk>P a t; P a s\<rbrakk> \<Longrightarrow> P a (App t s)) \<Longrightarrow> |
293 (\<And>a t s. \<lbrakk>P a t; P a s\<rbrakk> \<Longrightarrow> P a (App t s)) \<Longrightarrow> |
288 (\<And>a t. P a (Lam a t)) \<Longrightarrow> |
294 (\<And>a t. P a (Lam a t)) \<Longrightarrow> |
289 (\<And>a b t. \<lbrakk>a \<noteq> b; P a t\<rbrakk> \<Longrightarrow> P a (Lam b t)) \<Longrightarrow> P z za" |
295 (\<And>a b t. \<lbrakk>a \<noteq> b; P a t\<rbrakk> \<Longrightarrow> P a (Lam b t)) \<Longrightarrow> P z za" |
290 by (tactic {* ind_tac @{thms fresh_def} @{thms prem} |
296 by (tactic {* ind_tac @{thms fresh_def} @{thms prem} |
291 [@{cterm "P::string\<Rightarrow>trm\<Rightarrow>bool"}] *}) |
297 [@{cterm "P::string\<Rightarrow>trm\<Rightarrow>bool"}] *}) |
292 |
298 |
293 |
299 |
294 text {* |
300 text {* |
295 Let us have a closer look at the first proved theorem: |
301 While the tactic for proving the induction principles is relatively simple, |
|
302 it will be a bit of work to construct the goals from the introduction rules |
|
303 the user provides. Therefore let us have a closer look at the first |
|
304 proved theorem: |
296 |
305 |
297 \begin{isabelle} |
306 \begin{isabelle} |
298 \isacommand{thm}~@{thm [source] automatic_ind_prin_even}\\ |
307 \isacommand{thm}~@{thm [source] automatic_ind_prin_even}\\ |
299 @{text "> "}~@{thm automatic_ind_prin_even} |
308 @{text "> "}~@{thm automatic_ind_prin_even} |
300 \end{isabelle} |
309 \end{isabelle} |
301 |
310 |
302 The variables @{text "z"}, @{text "P"} and @{text "Q"} are schematic |
311 The variables @{text "z"}, @{text "P"} and @{text "Q"} are schematic |
303 variables (since they are not quantified in the lemma). These schematic |
312 variables (since they are not quantified in the lemma). These schematic |
304 variables are needed so that they can be instantiated by the user later |
313 variables are needed so that they can be instantiated by the user. |
305 on. We have to take care to also generate these schematic variables when |
314 We have to take care to also generate these schematic variables when |
306 generating the goals for the induction principles. While the tactic for |
315 generating the goals for the induction principles. In general we have |
307 proving the induction principles is relatively simple, it will be a bit |
316 to construct for each predicate @{text "pred"} a goal of the form |
308 of work to construct the goals from the introduction rules the user |
|
309 provides. In general we have to construct for each predicate @{text "pred"} |
|
310 a goal of the form |
|
311 |
317 |
312 @{text [display] |
318 @{text [display] |
313 "pred ?zs \<Longrightarrow> rules[preds := ?Ps] \<Longrightarrow> ?P ?zs"} |
319 "pred ?zs \<Longrightarrow> rules[preds := ?Ps] \<Longrightarrow> ?P ?zs"} |
314 |
320 |
315 where the predicates @{text preds} are replaced in the introduction |
321 where the predicates @{text preds} are replaced in @{text rules} by new |
316 rules by new distinct variables @{text "?Ps"}. |
322 distinct variables @{text "?Ps"}. We also need to generate fresh arguments |
317 We also need to generate fresh arguments @{text "?zs"} for the predicate |
323 @{text "?zs"} for the predicate @{text "pred"} and the @{text "?P"} in |
318 @{text "pred"} and the @{text "?P"} in the conclusion. Note |
324 the conclusion. The crucial point is that the @{text "?Ps"} and |
319 that the @{text "?Ps"} and @{text "?zs"} need to be |
325 @{text "?zs"} need to be schematic variables that can be instantiated |
320 schematic variables that can be instantiated by the user. |
326 by the user. |
321 |
327 |
322 We generate these goals in two steps. The first function expects that the |
328 We generate these goals in two steps. The first function, named @{text prove_ind}, |
323 introduction rules are already appropriately substituted. The argument |
329 expects that the introduction rules are already appropriately substituted. The argument |
324 @{text "srules"} stands for these substituted rules; @{text cnewpreds} are |
330 @{text "srules"} stands for these substituted rules; @{text cnewpreds} are |
325 the certified terms coresponding to the variables @{text "?Ps"}; @{text |
331 the certified terms coresponding to the variables @{text "?Ps"}; @{text |
326 "pred"} is the predicate for which we prove the induction principle; |
332 "pred"} is the predicate for which we prove the induction principle; |
327 @{text "newpred"} is its replacement and @{text "arg_tys"} are the argument |
333 @{text "newpred"} is its replacement and @{text "arg_tys"} are the argument |
328 types of this predicate. |
334 types of this predicate. |
361 tactic for proving the induction principle. As mentioned before, this tactic |
367 tactic for proving the induction principle. As mentioned before, this tactic |
362 expects the definitions, the premise and the (certified) predicates with |
368 expects the definitions, the premise and the (certified) predicates with |
363 which the introduction rules have been substituted. The code in these two |
369 which the introduction rules have been substituted. The code in these two |
364 lines will return a theorem. However, it is a theorem |
370 lines will return a theorem. However, it is a theorem |
365 proved inside the local theory @{text "lthy'"}, where the variables @{text |
371 proved inside the local theory @{text "lthy'"}, where the variables @{text |
366 "zs"} are fixed, but free (see Line 4). By exporting this theorem from @{text |
372 "zs"} are free, but fixed (see Line 4). By exporting this theorem from @{text |
367 "lthy'"} (which contains the @{text "zs"} as free variables) to @{text |
373 "lthy'"} (which contains the @{text "zs"} as free variables) to @{text |
368 "lthy"} (which does not), we obtain the desired schematic variables @{text "?zs"}. |
374 "lthy"} (which does not), we obtain the desired schematic variables @{text "?zs"}. |
369 A testcase for this function is |
375 A testcase for this function is |
370 *} |
376 *} |
371 |
377 |
372 local_setup %gray{* fn lthy => |
378 local_setup %gray{* fn lthy => |
373 let |
379 let |
374 val newpreds = [@{term "P::nat\<Rightarrow>bool"}, @{term "Q::nat\<Rightarrow>bool"}] |
380 val newpreds = [@{term "P::nat\<Rightarrow>bool"}, @{term "Q::nat\<Rightarrow>bool"}] |
375 val cnewpreds = [@{cterm "P::nat\<Rightarrow>bool"}, @{cterm "Q::nat\<Rightarrow>bool"}] |
381 val cnewpreds = [@{cterm "P::nat\<Rightarrow>bool"}, @{cterm "Q::nat\<Rightarrow>bool"}] |
|
382 val newpred = @{term "P::nat\<Rightarrow>bool"} |
376 val srules = map (subst_free (eo_preds ~~ newpreds)) eo_rules |
383 val srules = map (subst_free (eo_preds ~~ newpreds)) eo_rules |
377 val newpred = @{term "P::nat\<Rightarrow>bool"} |
|
378 val intro = |
384 val intro = |
379 prove_ind lthy eo_defs srules cnewpreds ((e_pred, newpred), e_arg_tys) |
385 prove_ind lthy eo_defs srules cnewpreds ((e_pred, newpred), e_arg_tys) |
380 in |
386 in |
381 warning (str_of_thm lthy intro); lthy |
387 warning (str_of_thm lthy intro); lthy |
382 end *} |
388 end *} |
383 |
389 |
384 text {* |
390 text {* |
416 end*} |
422 end*} |
417 |
423 |
418 text {* |
424 text {* |
419 In Line 3, we generate a string @{text [quotes] "P"} for each predicate. |
425 In Line 3, we generate a string @{text [quotes] "P"} for each predicate. |
420 In Line 4, we use the same trick as in the previous function, that is making the |
426 In Line 4, we use the same trick as in the previous function, that is making the |
421 @{text "Ps"} fresh and declaring them as fixed, but free, in |
427 @{text "Ps"} fresh and declaring them as free, but fixed, in |
422 the new local theory @{text "lthy'"}. From the local theory we extract |
428 the new local theory @{text "lthy'"}. From the local theory we extract |
423 the ambient theory in Line 6. We need this theory in order to certify |
429 the ambient theory in Line 6. We need this theory in order to certify |
424 the new predicates. In Line 8, we construct the types of these new predicates |
430 the new predicates. In Line 8, we construct the types of these new predicates |
425 using the given argument types. Next we turn them into terms and subsequently |
431 using the given argument types. Next we turn them into terms and subsequently |
426 certify them (Line 9 and 10). We can now produce the substituted introduction rules |
432 certify them (Line 9 and 10). We can now produce the substituted introduction rules |
564 respectively @{text "prems1"} and @{text "prems2"}. To do this |
570 respectively @{text "prems1"} and @{text "prems2"}. To do this |
565 separation, it is best to open a subproof with the tactic |
571 separation, it is best to open a subproof with the tactic |
566 @{ML SUBPROOF}, since this tactic provides us |
572 @{ML SUBPROOF}, since this tactic provides us |
567 with the parameters (as list of @{ML_type cterm}s) and the premises |
573 with the parameters (as list of @{ML_type cterm}s) and the premises |
568 (as list of @{ML_type thm}s). The problem we have to overcome |
574 (as list of @{ML_type thm}s). The problem we have to overcome |
569 with @{ML SUBPROOF} is that this tactic always expects us to completely |
575 with @{ML SUBPROOF} is, however, that this tactic always expects us to completely |
570 discharge with the goal (see Section ???). This is inconvenient for |
576 discharge the goal (see Section~\ref{sec:simpletacs}). This is inconvenient for |
571 our gradual explanation of the proof. To circumvent this inconvenience |
577 our gradual explanation of the proof here. To circumvent this inconvenience |
572 we use the following modified tactic: |
578 we use the following modified tactic: |
573 *} |
579 *} |
574 (*<*)oops(*>*) |
580 (*<*)oops(*>*) |
575 ML{*fun SUBPROOF_test tac ctxt = (SUBPROOF tac ctxt 1) ORELSE all_tac*} |
581 ML{*fun SUBPROOF_test tac ctxt = (SUBPROOF tac ctxt 1) ORELSE all_tac*} |
576 |
582 |
577 text {* |
583 text {* |
578 If the tactic inside @{ML SUBPROOF} fails, then the overall tactic will |
584 If the tactic inside @{ML SUBPROOF} fails, then the overall tactic will |
579 still succeed. With this testing tactic, we can gradually implement |
585 still succeed. With this testing tactic, we can gradually implement |
580 all necessary proof steps. |
586 all necessary proof steps inside a subproof. |
581 *} |
587 *} |
582 |
588 |
583 text_raw {* |
589 text_raw {* |
584 \begin{figure}[t] |
590 \begin{figure}[t] |
585 \begin{minipage}{\textwidth} |
591 \begin{minipage}{\textwidth} |
622 end) *} |
629 end) *} |
623 |
630 |
624 text {* |
631 text {* |
625 For the separation we can rely on that Isabelle deterministically |
632 For the separation we can rely on that Isabelle deterministically |
626 produces parameter and premises in a goal state. The last parameters |
633 produces parameter and premises in a goal state. The last parameters |
627 that were introduced, come from the quantifications in the definitions. |
634 that were introduced come from the quantifications in the definitions. |
628 Therefore we only have to subtract the number of predicates (in this |
635 Therefore we only have to subtract the number of predicates (in this |
629 case only @{text "1"} from the lenghts of all parameters. Similarly |
636 case only @{text "1"}) from the lenghts of all parameters. Similarly |
630 with the @{text "prems"}. The last premises in the goal state must |
637 with the @{text "prems"}: the last premises in the goal state come from |
631 come from unfolding of the conclusion. So we can just subtract |
638 unfolding the definition of the predicate in the conclusion. So we can |
632 the number of rules from the number of all premises. Applying |
639 just subtract the number of rules from the number of all premises. |
633 this tactic in our example |
640 Applying this tactic in our example |
634 *} |
641 *} |
635 |
642 |
636 (*<*) |
643 (*<*) |
637 lemma fresh_App: |
644 lemma fresh_Lam: |
638 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
645 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
639 apply(tactic {* expand_tac @{thms fresh_def} *}) |
646 apply(tactic {* expand_tac @{thms fresh_def} *}) |
640 (*>*) |
647 (*>*) |
641 apply(tactic {* chop_test_tac [fresh_pred] fresh_rules @{context} *}) |
648 apply(tactic {* chop_test_tac [fresh_pred] fresh_rules @{context} *}) |
642 (*<*)oops(*>*) |
649 (*<*)oops(*>*) |
669 that corresponds to the introduction rule we prove, namely: |
676 that corresponds to the introduction rule we prove, namely: |
670 |
677 |
671 @{term [display] "\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)"} |
678 @{term [display] "\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)"} |
672 |
679 |
673 To use this premise with @{ML rtac}, we need to instantiate its |
680 To use this premise with @{ML rtac}, we need to instantiate its |
674 quantifiers (with @{text params1}) and transform it into a |
681 quantifiers (with @{text params1}) and transform it into rule |
675 introduction rule (using @{ML "ObjectLogic.rulify"}. |
682 format (using @{ML "ObjectLogic.rulify"}. So we can modify the |
676 So we can modify the subproof as follows: |
683 subproof as follows: |
677 *} |
684 *} |
678 |
685 |
679 ML{*fun apply_prem_tac i preds rules = |
686 ML{*fun apply_prem_tac i preds rules = |
680 SUBPROOF_test (fn {params, prems, context, ...} => |
687 SUBPROOF_test (fn {params, prems, context, ...} => |
681 let |
688 let |
685 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
692 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
686 THEN print_tac "" |
693 THEN print_tac "" |
687 THEN no_tac |
694 THEN no_tac |
688 end) *} |
695 end) *} |
689 |
696 |
690 text {* and apply it with *} |
697 text {* |
|
698 The argument @{text i} corresponds to the number of the |
|
699 introduction we want to analyse. We will later on lat it range |
|
700 from @{text 0} to the number of introduction rules. |
|
701 Below we applying this function with @{text 3}, since |
|
702 we are proving the fourth introduction rule. |
|
703 *} |
691 |
704 |
692 (*<*) |
705 (*<*) |
693 lemma fresh_App: |
706 lemma fresh_Lam: |
694 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
707 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
695 apply(tactic {* expand_tac @{thms fresh_def} *}) |
708 apply(tactic {* expand_tac @{thms fresh_def} *}) |
696 (*>*) |
709 (*>*) |
697 apply(tactic {* apply_prem_tac 3 [fresh_pred] fresh_rules @{context} *}) |
710 apply(tactic {* apply_prem_tac 3 [fresh_pred] fresh_rules @{context} *}) |
698 (*<*)oops(*>*) |
711 (*<*)oops(*>*) |
699 |
712 |
700 text {* |
713 text {* |
701 Since we print out the goal state after the @{ML rtac} we can see |
714 Since we print out the goal state just after the application of |
702 the goal state has the two subgoals |
715 @{ML rtac}, we can see the goal state we obtain: as expected it has |
|
716 the two subgoals |
703 |
717 |
704 \begin{isabelle} |
718 \begin{isabelle} |
705 @{text "1."}~@{prop "a \<noteq> b"}\\ |
719 @{text "1."}~@{prop "a \<noteq> b"}\\ |
706 @{text "2."}~@{prop "fresh a t"} |
720 @{text "2."}~@{prop "fresh a t"} |
707 \end{isabelle} |
721 \end{isabelle} |
708 |
722 |
709 where the first comes from a non-recursive precondition of the rule |
723 where the first comes from a non-recursive premise of the rule |
710 and the second comes from a recursive precondition. The first kind |
724 and the second comes from a recursive premise. The first goal |
711 can be solved immediately by @{text "prems1"}. The second kind |
725 can be solved immediately by @{text "prems1"}. The second |
712 needs more work. It can be solved with the other premise in @{text "prems1"}, |
726 needs more work. It can be solved with the other premise |
713 namely |
727 in @{text "prems1"}, namely |
714 |
728 |
715 @{term [break,display] |
729 @{term [break,display] |
716 "\<forall>fresh. |
730 "\<forall>fresh. |
717 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
731 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
718 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
732 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
720 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"} |
734 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"} |
721 |
735 |
722 but we have to instantiate it appropriately. These instantiations |
736 but we have to instantiate it appropriately. These instantiations |
723 come from @{text "params1"} and @{text "prems2"}. We can determine |
737 come from @{text "params1"} and @{text "prems2"}. We can determine |
724 whether we are in the simple or complicated case by checking whether |
738 whether we are in the simple or complicated case by checking whether |
725 the topmost connective is @{text "\<forall>"}. The premises in the simple |
739 the topmost connective is an @{text "\<forall>"}. The premises in the simple |
726 case cannot have such a quantification, since in the first step |
740 case cannot have such a quantification, since in the first step |
727 of @{ML "expand_tac"} was the ``rulification'' of the lemma. So |
741 of @{ML "expand_tac"} was the ``rulification'' of the lemma. |
|
742 The premise of the complicated case must have at least one @{text "\<forall>"} |
|
743 coming from the quantification over the @{text preds}. So |
728 we can implement the following function |
744 we can implement the following function |
729 *} |
745 *} |
730 |
746 |
731 ML{*fun prepare_prem params2 prems2 prem = |
747 ML{*fun prepare_prem params2 prems2 prem = |
732 rtac (case prop_of prem of |
748 rtac (case prop_of prem of |
734 prem |> all_elims params2 |
750 prem |> all_elims params2 |
735 |> imp_elims prems2 |
751 |> imp_elims prems2 |
736 | _ => prem) *} |
752 | _ => prem) *} |
737 |
753 |
738 text {* |
754 text {* |
739 which either applies the premise outright or if it had an |
755 which either applies the premise outright (the default case) or if |
740 outermost universial quantification, instantiates it first with |
756 it has an outermost universial quantification, instantiates it first |
741 @{text "params1"} and then @{text "prems1"}. The following tactic |
757 with @{text "params1"} and then @{text "prems1"}. The following |
742 will therefore prove the lemma. |
758 tactic will therefore prove the lemma completely. |
743 *} |
759 *} |
744 |
760 |
745 ML{*fun prove_intro_tac i preds rules = |
761 ML{*fun prove_intro_tac i preds rules = |
746 SUBPROOF (fn {params, prems, context, ...} => |
762 SUBPROOF (fn {params, prems, ...} => |
747 let |
763 let |
748 val (params1, params2) = chop (length params - length preds) params |
764 val (params1, params2) = chop (length params - length preds) params |
749 val (prems1, prems2) = chop (length prems - length rules) prems |
765 val (prems1, prems2) = chop (length prems - length rules) prems |
750 in |
766 in |
751 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
767 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
752 THEN EVERY1 (map (prepare_prem params2 prems2) prems1) |
768 THEN EVERY1 (map (prepare_prem params2 prems2) prems1) |
753 end) *} |
769 end) *} |
754 |
770 |
755 text {* |
771 text {* |
756 We can complete the proof of the introduction rule now as follows: |
772 The full proof of the introduction rule now as follows: |
757 *} |
773 *} |
758 |
774 |
759 (*<*) |
775 lemma fresh_Lam: |
760 lemma fresh_App: |
|
761 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
776 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
762 apply(tactic {* expand_tac @{thms fresh_def} *}) |
777 apply(tactic {* expand_tac @{thms fresh_def} *}) |
763 (*>*) |
|
764 apply(tactic {* prove_intro_tac 3 [fresh_pred] fresh_rules @{context} 1 *}) |
778 apply(tactic {* prove_intro_tac 3 [fresh_pred] fresh_rules @{context} 1 *}) |
765 done |
779 done |
766 |
780 |
767 text {* |
781 text {* |
768 Unfortunately, not everything is done yet. |
782 Unfortunately, not everything is done yet. If you look closely |
|
783 at the general principle outlined in Section~\ref{sec:nutshell}, |
|
784 we have not yet dealt with the case when recursive premises |
|
785 in a rule have preconditions @{text Bs}. The introduction rule |
|
786 of the accessible part is such a rule. |
769 *} |
787 *} |
770 |
788 |
771 lemma accpartI: |
789 lemma accpartI: |
772 shows "\<And>x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
790 shows "\<And>x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
773 apply(tactic {* expand_tac @{thms accpart_def} *}) |
791 apply(tactic {* expand_tac @{thms accpart_def} *}) |
774 apply(tactic {* chop_test_tac [acc_pred] acc_rules @{context} *}) |
792 apply(tactic {* chop_test_tac [acc_pred] acc_rules @{context} *}) |
775 apply(tactic {* apply_prem_tac 0 [acc_pred] acc_rules @{context} *}) |
793 apply(tactic {* apply_prem_tac 0 [acc_pred] acc_rules @{context} *}) |
776 |
794 |
777 txt {* |
795 txt {* |
778 |
796 Here @{ML chop_test_tac} prints out the following |
779 @{subgoals [display]} |
797 values for @{text "params1/2"} and @{text "prems1/2"} |
780 |
798 |
781 \begin{isabelle} |
799 \begin{isabelle} |
782 @{text "Params1 from the rule:"}\\ |
800 @{text "Params1 from the rule:"}\\ |
783 @{text "x"}\\ |
801 @{text "x"}\\ |
784 @{text "Params2 from the predicate:"}\\ |
802 @{text "Params2 from the predicate:"}\\ |
787 @{text "R ?y x \<Longrightarrow> \<forall>P. (\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x) \<longrightarrow> P ?y"}\\ |
805 @{text "R ?y x \<Longrightarrow> \<forall>P. (\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x) \<longrightarrow> P ?y"}\\ |
788 @{text "Prems2 from the predicate:"}\\ |
806 @{text "Prems2 from the predicate:"}\\ |
789 @{term "\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x"}\\ |
807 @{term "\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x"}\\ |
790 \end{isabelle} |
808 \end{isabelle} |
791 |
809 |
792 *} |
810 and after application of the introduction rule |
793 (*<*)oops(*>*) |
811 using @{ML apply_prem_tac}, we are in the goal state |
794 |
812 |
795 |
813 \begin{isabelle} |
796 ML{*fun prepare_prem params2 prems2 ctxt prem = |
814 @{text "1."}~@{term "\<And>y. R y x \<Longrightarrow> P y"} |
|
815 \end{isabelle} |
|
816 |
|
817 |
|
818 *}(*<*)oops(*>*) |
|
819 |
|
820 text {* |
|
821 In order to make progress as before, we have to use the precondition |
|
822 @{text "R y x"} (in general there can be many of them). The best way |
|
823 to get a handle on these preconditions is to open up another subproof, |
|
824 since the preconditions will be bound to @{text prems}. Therfore we |
|
825 modify the function @{ML prepare_prem} as follows |
|
826 *} |
|
827 |
|
828 ML %linenosgray{*fun prepare_prem params2 prems2 ctxt prem = |
797 SUBPROOF (fn {prems, ...} => |
829 SUBPROOF (fn {prems, ...} => |
798 let |
830 let |
799 val prem' = prems MRS prem |
831 val prem' = prems MRS prem |
800 in |
832 in |
801 rtac (case prop_of prem' of |
833 rtac (case prop_of prem' of |
803 prem' |> all_elims params2 |
835 prem' |> all_elims params2 |
804 |> imp_elims prems2 |
836 |> imp_elims prems2 |
805 | _ => prem') 1 |
837 | _ => prem') 1 |
806 end) ctxt *} |
838 end) ctxt *} |
807 |
839 |
808 ML{*fun prove_intro_tac i preds rules = |
840 text {* |
|
841 In Line 4 we use the @{text prems} from the @{ML SUBPROOF} and resolve |
|
842 them with @{text prem}. In the simple case, that is where the @{text prem} |
|
843 comes from a non-recursive premise of the rule, @{text prems} will be |
|
844 just the empty list and the @{ML MRS} does nothing. Similarly, in the |
|
845 cases where the recursive premises of the rule do not have preconditions. |
|
846 |
|
847 The function @{ML prove_intro_tac} only needs to give the context to |
|
848 @{ML prepare_prem} (Line 8) and is as follows. |
|
849 *} |
|
850 |
|
851 ML %linenosgray{*fun prove_intro_tac i preds rules = |
809 SUBPROOF (fn {params, prems, context, ...} => |
852 SUBPROOF (fn {params, prems, context, ...} => |
810 let |
853 let |
811 val (params1, params2) = chop (length params - length preds) params |
854 val (params1, params2) = chop (length params - length preds) params |
812 val (prems1, prems2) = chop (length prems - length rules) prems |
855 val (prems1, prems2) = chop (length prems - length rules) prems |
813 in |
856 in |
814 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
857 rtac (ObjectLogic.rulify (all_elims params1 (nth prems2 i))) 1 |
815 THEN EVERY1 (map (prepare_prem params2 prems2 context) prems1) |
858 THEN EVERY1 (map (prepare_prem params2 prems2 context) prems1) |
816 end) *} |
859 end) *} |
817 |
860 |
|
861 text {* |
|
862 With these extended function we can also prove the introduction |
|
863 rule for the accessible part. |
|
864 *} |
|
865 |
818 lemma accpartI: |
866 lemma accpartI: |
819 shows "\<And>x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
867 shows "\<And>x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
820 apply(tactic {* expand_tac @{thms accpart_def} *}) |
868 apply(tactic {* expand_tac @{thms accpart_def} *}) |
821 apply(tactic {* prove_intro_tac 0 [acc_pred] acc_rules @{context} 1 *}) |
869 apply(tactic {* prove_intro_tac 0 [acc_pred] acc_rules @{context} 1 *}) |
822 done |
870 done |
823 |
871 |
824 |
872 text {* |
825 |
873 Finally we need two functions that string everything together. The first |
826 text {* |
874 function is the tactic that performs the proofs. |
827 |
875 *} |
828 *} |
876 |
829 |
877 ML %linenosgray{*fun intro_tac defs rules preds i ctxt = |
830 ML{* |
|
831 fun intros_tac defs rules preds i ctxt = |
|
832 EVERY1 [ObjectLogic.rulify_tac, |
878 EVERY1 [ObjectLogic.rulify_tac, |
833 K (rewrite_goals_tac defs), |
879 K (rewrite_goals_tac defs), |
834 REPEAT o (resolve_tac [@{thm allI}, @{thm impI}]), |
880 REPEAT o (resolve_tac [@{thm allI}, @{thm impI}]), |
835 prove_intro_tac i preds rules ctxt]*} |
881 prove_intro_tac i preds rules ctxt]*} |
836 |
882 |
837 text {* |
883 text {* |
838 A test case |
884 Lines 2 to 4 correspond to the function @{ML expand_tac}. Some testcases |
839 *} |
885 dor this tactic are: |
840 |
886 *} |
841 ML{*fun intros_tac_test ctxt i = |
887 |
842 intros_tac eo_defs eo_rules eo_preds i ctxt *} |
888 lemma even0_intro: |
843 |
|
844 lemma intro0: |
|
845 shows "even 0" |
889 shows "even 0" |
846 apply(tactic {* intros_tac_test @{context} 0 *}) |
890 by (tactic {* intro_tac eo_defs eo_rules eo_preds 0 @{context} *}) |
847 done |
891 |
848 |
892 |
849 lemma intro1: |
893 lemma evenS_intro: |
850 shows "\<And>m. odd m \<Longrightarrow> even (Suc m)" |
894 shows "\<And>m. odd m \<Longrightarrow> even (Suc m)" |
851 apply(tactic {* intros_tac_test @{context} 1 *}) |
895 by (tactic {* intro_tac eo_defs eo_rules eo_preds 1 @{context} *}) |
852 done |
896 |
853 |
897 lemma fresh_App: |
854 lemma intro2: |
898 shows "\<And>a t s. \<lbrakk>fresh a t; fresh a s\<rbrakk> \<Longrightarrow> fresh a (App t s)" |
855 shows "\<And>m. even m \<Longrightarrow> odd (Suc m)" |
899 by (tactic {* |
856 apply(tactic {* intros_tac_test @{context} 2 *}) |
900 intro_tac @{thms fresh_def} fresh_rules [fresh_pred] 1 @{context} *}) |
857 done |
901 |
858 |
902 text {* |
859 ML{*fun intros rules preds defs lthy = |
903 The second function sets up in Line 4 the goals (in this case this is easy |
|
904 since they are exactly the introduction rules the user gives) |
|
905 and iterates @{ML intro_tac} over all introduction rules. |
|
906 *} |
|
907 |
|
908 ML %linenosgray{*fun intros rules preds defs lthy = |
860 let |
909 let |
861 fun prove_intro (i, goal) = |
910 fun intros_aux (i, goal) = |
862 Goal.prove lthy [] [] goal |
911 Goal.prove lthy [] [] goal |
863 (fn {context, ...} => intros_tac defs rules preds i context) |
912 (fn {context, ...} => intro_tac defs rules preds i context) |
864 in |
913 in |
865 map_index prove_intro rules |
914 map_index intros_aux rules |
866 end*} |
915 end*} |
867 |
916 |
|
917 subsection {* Main Function *} |
|
918 |
868 text {* main internal function *} |
919 text {* main internal function *} |
|
920 |
|
921 ML {* LocalTheory.notes *} |
|
922 |
869 |
923 |
870 ML %linenosgray{*fun add_inductive pred_specs rule_specs lthy = |
924 ML %linenosgray{*fun add_inductive pred_specs rule_specs lthy = |
871 let |
925 let |
872 val syns = map snd pred_specs |
926 val syns = map snd pred_specs |
873 val pred_specs' = map fst pred_specs |
927 val pred_specs' = map fst pred_specs |