diff --git a/src/Doc/Codegen/Inductive_Predicate.thy b/src/Doc/Codegen/Inductive_Predicate.thy --- a/src/Doc/Codegen/Inductive_Predicate.thy +++ b/src/Doc/Codegen/Inductive_Predicate.thy @@ -1,268 +1,268 @@ theory Inductive_Predicate imports Setup begin (*<*) hide_const %invisible append inductive %invisible append where "append [] ys ys" | "append xs ys zs \ append (x # xs) ys (x # zs)" lemma %invisible append: "append xs ys zs = (xs @ ys = zs)" by (induct xs arbitrary: ys zs) (auto elim: append.cases intro: append.intros) lemmas lexordp_def = lexordp_def [unfolded lexord_def mem_Collect_eq split] (*>*) section \Inductive Predicates \label{sec:inductive}\ text \ The \predicate compiler\ is an extension of the code generator which turns inductive specifications into equational ones, from which in turn executable code can be generated. The mechanisms of this compiler are described in detail in @{cite "Berghofer-Bulwahn-Haftmann:2009:TPHOL"}. Consider the simple predicate \<^const>\append\ given by these two introduction rules: \ text %quote \ @{thm append.intros(1)[of ys]} \\ @{thm append.intros(2)[of xs ys zs x]} \ text \ \noindent To invoke the compiler, simply use @{command_def "code_pred"}: \ code_pred %quote append . text \ \noindent The @{command "code_pred"} command takes the name of the inductive predicate and then you put a period to discharge a trivial correctness proof. The compiler infers possible modes for the predicate and produces the derived code equations. Modes annotate which (parts of the) arguments are to be taken as input, and which output. Modes are similar to types, but use the notation \i\ for input and \o\ for output. For \<^term>\append\, the compiler can infer the following modes: \begin{itemize} \item \i \ i \ i \ bool\ \item \i \ i \ o \ bool\ \item \o \ o \ i \ bool\ \end{itemize} You can compute sets of predicates using @{command_def "values"}: \ values %quote "{zs. append [(1::nat),2,3] [4,5] zs}" text \\noindent outputs \{[1, 2, 3, 4, 5]}\, and\ values %quote "{(xs, ys). append xs ys [(2::nat),3]}" text \\noindent outputs \{([], [2, 3]), ([2], [3]), ([2, 3], [])}\.\ text \ \noindent If you are only interested in the first elements of the set comprehension (with respect to a depth-first search on the introduction rules), you can pass an argument to @{command "values"} to specify the number of elements you want: \ values %quote 1 "{(xs, ys). append xs ys [(1::nat), 2, 3, 4]}" values %quote 3 "{(xs, ys). append xs ys [(1::nat), 2, 3, 4]}" text \ \noindent The @{command "values"} command can only compute set comprehensions for which a mode has been inferred. The code equations for a predicate are made available as theorems with the suffix \equation\, and can be inspected with: \ thm %quote append.equation text \ \noindent More advanced options are described in the following subsections. \ subsection \Alternative names for functions\ text \ By default, the functions generated from a predicate are named after the predicate with the mode mangled into the name (e.g., \append_i_i_o\). You can specify your own names as follows: \ code_pred %quote (modes: i \ i \ o \ bool as concat, o \ o \ i \ bool as split, i \ o \ i \ bool as suffix) append . subsection \Alternative introduction rules\ text \ Sometimes the introduction rules of an predicate are not executable because they contain non-executable constants or specific modes could not be inferred. It is also possible that the introduction rules yield a function that loops forever due to the execution in a depth-first search manner. Therefore, you can declare alternative introduction rules for predicates with the attribute @{attribute "code_pred_intro"}. For example, the transitive closure is defined by: \ text %quote \ @{lemma [source] "r a b \ tranclp r a b" by (fact tranclp.intros(1))}\\ @{lemma [source] "tranclp r a b \ r b c \ tranclp r a c" by (fact tranclp.intros(2))} \ text \ \noindent These rules do not suit well for executing the transitive closure with the mode \(i \ o \ bool) \ i \ o \ bool\, as the second rule will cause an infinite loop in the recursive call. This can be avoided using the following alternative rules which are declared to the predicate compiler by the attribute @{attribute "code_pred_intro"}: \ lemma %quote [code_pred_intro]: "r a b \ tranclp r a b" "r a b \ tranclp r b c \ tranclp r a c" by auto text \ \noindent After declaring all alternative rules for the transitive closure, you invoke @{command "code_pred"} as usual. As you have declared alternative rules for the predicate, you are urged to prove that these introduction rules are complete, i.e., that you can derive an elimination rule for the alternative rules: \ code_pred %quote tranclp proof - case tranclp from this converse_tranclpE [OF tranclp.prems] show thesis by metis qed text \ \noindent Alternative rules can also be used for constants that have not been defined inductively. For example, the lexicographic order which is defined as: \ text %quote \ @{thm [display] lexordp_def [of r]} \ text \ \noindent To make it executable, you can derive the following two rules and prove the elimination rule: \ lemma %quote [code_pred_intro]: "append xs (a # v) ys \ lexordp r xs ys" (*<*)unfolding lexordp_def by (auto simp add: append)(*>*) lemma %quote [code_pred_intro]: - "append u (a # v) xs \ append u (b # w) ys \ r a b + "append u (a # v) xs \ append u (b # w) ys \ r a b \ a\b \ lexordp r xs ys" (*<*)unfolding lexordp_def append apply simp apply (rule disjI2) by auto(*>*) code_pred %quote lexordp (*<*)proof - fix r xs ys assume lexord: "lexordp r xs ys" assume 1: "\r' xs' ys' a v. r = r' \ xs = xs' \ ys = ys' \ append xs' (a # v) ys' \ thesis" assume 2: "\r' xs' ys' u a v b w. r = r' \ xs = xs' \ ys = ys' - \ append u (a # v) xs' \ append u (b # w) ys' \ r' a b \ thesis" + \ append u (a # v) xs' \ append u (b # w) ys' \ r' a b \ a\b \ thesis" { assume "\a v. ys = xs @ a # v" from this 1 have thesis by (fastforce simp add: append) } moreover { - assume "\u a b v w. r a b \ xs = u @ a # v \ ys = u @ b # w" + assume "\u a b v w. r a b \ a\b \ xs = u @ a # v \ ys = u @ b # w" from this 2 have thesis by (fastforce simp add: append) } moreover note lexord ultimately show thesis unfolding lexordp_def by fastforce qed(*>*) subsection \Options for values\ text \ In the presence of higher-order predicates, multiple modes for some predicate could be inferred that are not disambiguated by the pattern of the set comprehension. To disambiguate the modes for the arguments of a predicate, you can state the modes explicitly in the @{command "values"} command. Consider the simple predicate \<^term>\succ\: \ inductive %quote succ :: "nat \ nat \ bool" where "succ 0 (Suc 0)" | "succ x y \ succ (Suc x) (Suc y)" code_pred %quote succ . text \ \noindent For this, the predicate compiler can infer modes \o \ o \ bool\, \i \ o \ bool\, \o \ i \ bool\ and \i \ i \ bool\. The invocation of @{command "values"} \{n. tranclp succ 10 n}\ loops, as multiple modes for the predicate \succ\ are possible and here the first mode \o \ o \ bool\ is chosen. To choose another mode for the argument, you can declare the mode for the argument between the @{command "values"} and the number of elements. \ values %quote [mode: i \ o \ bool] 1 "{n. tranclp succ 10 n}" (*FIXME does not terminate for n\1*) values %quote [mode: o \ i \ bool] 1 "{n. tranclp succ n 10}" subsection \Embedding into functional code within Isabelle/HOL\ text \ To embed the computation of an inductive predicate into functions that are defined in Isabelle/HOL, you have a number of options: \begin{itemize} \item You want to use the first-order predicate with the mode where all arguments are input. Then you can use the predicate directly, e.g. @{text [display] \valid_suffix ys zs = (if append [Suc 0, 2] ys zs then Some ys else None)\} \item If you know that the execution returns only one value (it is deterministic), then you can use the combinator \<^term>\Predicate.the\, e.g., a functional concatenation of lists is defined with @{term [display] "functional_concat xs ys = Predicate.the (append_i_i_o xs ys)"} Note that if the evaluation does not return a unique value, it raises a run-time error \<^term>\not_unique\. \end{itemize} \ subsection \Further Examples\ text \ Further examples for compiling inductive predicates can be found in \<^file>\~~/src/HOL/Predicate_Compile_Examples/Examples.thy\. There are also some examples in the Archive of Formal Proofs, notably in the \POPLmark-deBruijn\ and the \FeatherweightJava\ sessions. \ end diff --git a/src/HOL/MicroJava/DFA/Kildall.thy b/src/HOL/MicroJava/DFA/Kildall.thy --- a/src/HOL/MicroJava/DFA/Kildall.thy +++ b/src/HOL/MicroJava/DFA/Kildall.thy @@ -1,485 +1,489 @@ (* Title: HOL/MicroJava/DFA/Kildall.thy Author: Tobias Nipkow, Gerwin Klein Copyright 2000 TUM *) section \Kildall's Algorithm \label{sec:Kildall}\ theory Kildall imports SemilatAlg "HOL-Library.While_Combinator" begin primrec propa :: "'s binop \ (nat \ 's) list \ 's list \ nat set \ 's list * nat set" where "propa f [] ss w = (ss,w)" | "propa f (q'#qs) ss w = (let (q,t) = q'; u = t +_f ss!q; w' = (if u = ss!q then w else insert q w) in propa f qs (ss[q := u]) w')" definition iter :: "'s binop \ 's step_type \ 's list \ nat set \ 's list \ nat set" where "iter f step ss w == while (%(ss,w). w \ {}) (%(ss,w). let p = SOME p. p \ w in propa f (step p (ss!p)) ss (w-{p})) (ss,w)" definition unstables :: "'s ord \ 's step_type \ 's list \ nat set" where "unstables r step ss == {p. p < size ss \ \stable r step ss p}" definition kildall :: "'s ord \ 's binop \ 's step_type \ 's list \ 's list" where "kildall r f step ss == fst(iter f step ss (unstables r step ss))" primrec merges :: "'s binop \ (nat \ 's) list \ 's list \ 's list" where "merges f [] ss = ss" | "merges f (p'#ps) ss = (let (p,s) = p' in merges f ps (ss[p := s +_f ss!p]))" lemmas [simp] = Let_def Semilat.le_iff_plus_unchanged [OF Semilat.intro, symmetric] lemma (in Semilat) nth_merges: "\ss. \p < length ss; ss \ list n A; \(p,t)\set ps. p t\A \ \ (merges f ps ss)!p = map snd [(p',t') \ ps. p'=p] ++_f ss!p" (is "\ss. \_; _; ?steptype ps\ \ ?P ss ps") proof (induct ps) show "\ss. ?P ss []" by simp fix ss p' ps' assume ss: "ss \ list n A" assume l: "p < length ss" assume "?steptype (p'#ps')" then obtain a b where p': "p'=(a,b)" and ab: "aA" and ps': "?steptype ps'" by (cases p') auto assume "\ss. p< length ss \ ss \ list n A \ ?steptype ps' \ ?P ss ps'" from this [OF _ _ ps'] have IH: "\ss. ss \ list n A \ p < length ss \ ?P ss ps'" . from ss ab have "ss[a := b +_f ss!a] \ list n A" by (simp add: closedD) moreover from calculation l have "p < length (ss[a := b +_f ss!a])" by simp ultimately have "?P (ss[a := b +_f ss!a]) ps'" by (rule IH) with p' l show "?P ss (p'#ps')" by simp qed (** merges **) lemma length_merges [simp]: "size(merges f ps ss) = size ss" by (induct ps arbitrary: ss) auto lemma (in Semilat) merges_preserves_type_lemma: shows "\xs. xs \ list n A \ (\(p,x) \ set ps. p x\A) \ merges f ps xs \ list n A" apply (insert closedI) apply (unfold closed_def) apply (induct_tac ps) apply simp apply clarsimp done lemma (in Semilat) merges_preserves_type [simp]: "\ xs \ list n A; \(p,x) \ set ps. p x\A \ \ merges f ps xs \ list n A" by (simp add: merges_preserves_type_lemma) lemma (in Semilat) merges_incr_lemma: "\xs. xs \ list n A \ (\(p,x)\set ps. p x \ A) \ xs <=[r] merges f ps xs" apply (induct_tac ps) apply simp apply simp apply clarify apply (rule order_trans) apply simp apply (erule list_update_incr) apply simp apply simp apply (blast intro!: listE_set intro: closedD listE_length [THEN nth_in]) done lemma (in Semilat) merges_incr: "\ xs \ list n A; \(p,x)\set ps. p x \ A \ \ xs <=[r] merges f ps xs" by (simp add: merges_incr_lemma) lemma (in Semilat) merges_same_conv [rule_format]: "(\xs. xs \ list n A \ (\(p,x)\set ps. p x\A) \ (merges f ps xs = xs) = (\(p,x)\set ps. x <=_r xs!p))" apply (induct_tac ps) apply simp apply clarsimp apply (rename_tac p x ps xs) apply (rule iffI) apply (rule context_conjI) apply (subgoal_tac "xs[p := x +_f xs!p] <=[r] xs") apply (drule_tac p = p in le_listD) apply simp apply simp apply (erule subst, rule merges_incr) apply (blast intro!: listE_set intro: closedD listE_length [THEN nth_in]) apply clarify apply (rule conjI) apply simp apply (blast dest: boundedD) apply blast apply clarify apply (erule allE) apply (erule impE) apply assumption apply (drule bspec) apply assumption apply (simp add: le_iff_plus_unchanged [THEN iffD1] list_update_same_conv [THEN iffD2]) apply blast apply clarify apply (simp add: le_iff_plus_unchanged [THEN iffD1] list_update_same_conv [THEN iffD2]) done lemma (in Semilat) list_update_le_listI [rule_format]: "set xs <= A \ set ys <= A \ xs <=[r] ys \ p < size xs \ x <=_r ys!p \ x\A \ xs[p := x +_f xs!p] <=[r] ys" apply(insert semilat) apply (unfold Listn.le_def lesub_def semilat_def) apply (simp add: list_all2_conv_all_nth nth_list_update) done lemma (in Semilat) merges_pres_le_ub: assumes "set ts <= A" and "set ss <= A" and "\(p,t)\set ps. t <=_r ts!p \ t \ A \ p < size ts" and "ss <=[r] ts" shows "merges f ps ss <=[r] ts" proof - { fix t ts ps have "\qs. \set ts <= A; \(p,t)\set ps. t <=_r ts!p \ t \ A \ p< size ts \ \ set qs <= set ps \ (\ss. set ss <= A \ ss <=[r] ts \ merges f qs ss <=[r] ts)" apply (induct_tac qs) apply simp apply (simp (no_asm_simp)) apply clarify apply (rotate_tac -2) apply simp apply (erule allE, erule impE, erule_tac [2] mp) apply (drule bspec, assumption) apply (simp add: closedD) apply (drule bspec, assumption) apply (simp add: list_update_le_listI) done } note this [dest] from assms show ?thesis by blast qed (** propa **) lemma decomp_propa: "\ss w. (\(q,t)\set qs. q < size ss) \ propa f qs ss w = (merges f qs ss, {q. \t. (q,t)\set qs \ t +_f ss!q \ ss!q} Un w)" apply (induct qs) apply simp apply (simp (no_asm)) apply clarify apply simp apply (rule conjI) apply blast apply (simp add: nth_list_update) apply blast done (** iter **) lemma (in Semilat) stable_pres_lemma: shows "\pres_type step n A; bounded step n; ss \ list n A; p \ w; \q\w. q < n; \q. q < n \ q \ w \ stable r step ss q; q < n; \s'. (q,s') \ set (step p (ss ! p)) \ s' +_f ss ! q = ss ! q; q \ w \ q = p \ \ stable r step (merges f (step p (ss!p)) ss) q" apply (unfold stable_def) apply (subgoal_tac "\s'. (q,s') \ set (step p (ss!p)) \ s' \ A") prefer 2 apply clarify apply (erule pres_typeD) prefer 3 apply assumption apply (rule listE_nth_in) apply assumption apply simp apply simp apply simp apply clarify apply (subst nth_merges) apply simp apply (blast dest: boundedD) apply assumption apply clarify apply (rule conjI) apply (blast dest: boundedD) apply (erule pres_typeD) prefer 3 apply assumption apply simp apply simp apply(subgoal_tac "q < length ss") prefer 2 apply simp apply (frule nth_merges [of q _ _ "step p (ss!p)"]) (* fixme: why does method subst not work?? *) apply assumption apply clarify apply (rule conjI) apply (blast dest: boundedD) apply (erule pres_typeD) prefer 3 apply assumption apply simp apply simp apply (drule_tac P = "\x. (a, b) \ set (step q x)" in subst) apply assumption apply (simp add: plusplus_empty) apply (cases "q \ w") apply simp apply (rule ub1') apply (rule semilat) apply clarify apply (rule pres_typeD) apply assumption prefer 3 apply assumption apply (blast intro: listE_nth_in dest: boundedD) apply (blast intro: pres_typeD dest: boundedD) apply (blast intro: listE_nth_in dest: boundedD) apply assumption apply simp apply (erule allE, erule impE, assumption, erule impE, assumption) apply (rule order_trans) apply simp defer apply (rule pp_ub2)(* apply assumption*) apply simp apply clarify apply simp apply (rule pres_typeD) apply assumption prefer 3 apply assumption apply (blast intro: listE_nth_in dest: boundedD) apply (blast intro: pres_typeD dest: boundedD) apply (blast intro: listE_nth_in dest: boundedD) apply blast done lemma (in Semilat) merges_bounded_lemma: "\ mono r step n A; bounded step n; \(p',s') \ set (step p (ss!p)). s' \ A; ss \ list n A; ts \ list n A; p < n; ss <=[r] ts; \p. p < n \ stable r step ts p \ \ merges f (step p (ss!p)) ss <=[r] ts" apply (unfold stable_def) apply (rule merges_pres_le_ub) apply simp apply simp prefer 2 apply assumption apply clarsimp apply (drule boundedD, assumption+) apply (erule allE, erule impE, assumption) apply (drule bspec, assumption) apply simp apply (drule monoD [of _ _ _ _ p "ss!p" "ts!p"]) apply assumption apply simp apply (simp add: le_listD) apply (drule lesub_step_typeD, assumption) apply clarify apply (drule bspec, assumption) apply simp apply (blast intro: order_trans) done lemma termination_lemma: assumes semilat: "semilat (A, r, f)" shows "\ ss \ list n A; \(q,t)\set qs. q t\A; p\w \ \ ss <[r] merges f qs ss \ merges f qs ss = ss \ {q. \t. (q,t)\set qs \ t +_f ss!q \ ss!q} Un (w-{p}) < w" (is "PROP ?P") proof - interpret Semilat A r f using assms by (rule Semilat.intro) show "PROP ?P" apply(insert semilat) apply (unfold lesssub_def) apply (simp (no_asm_simp) add: merges_incr) apply (rule impI) apply (rule merges_same_conv [THEN iffD1, elim_format]) apply assumption+ defer apply (rule sym, assumption) defer apply simp apply (subgoal_tac "\q t. \((q, t) \ set qs \ t +_f ss ! q \ ss ! q)") apply (blast elim: equalityE) apply clarsimp apply (drule bspec, assumption) apply (drule bspec, assumption) apply clarsimp done qed +(*for lex*) +lemma ne_lesssub_iff [simp]: "y\x \ x <[r] y \ x <[r] y" + by (meson lesssub_def) + lemma iter_properties[rule_format]: assumes semilat: "semilat (A, r, f)" shows "\ acc r ; pres_type step n A; mono r step n A; bounded step n; \p\w0. p < n; ss0 \ list n A; \p w0 \ stable r step ss0 p \ \ iter f step ss0 w0 = (ss',w') \ ss' \ list n A \ stables r step ss' \ ss0 <=[r] ss' \ (\ts\list n A. ss0 <=[r] ts \ stables r step ts \ ss' <=[r] ts)" (is "PROP ?P") proof - interpret Semilat A r f using assms by (rule Semilat.intro) show "PROP ?P" apply(insert semilat) apply (unfold iter_def stables_def) apply (rule_tac P = "%(ss,w). ss \ list n A \ (\p w \ stable r step ss p) \ ss0 <=[r] ss \ (\ts\list n A. ss0 <=[r] ts \ stables r step ts \ ss <=[r] ts) \ (\p\w. p < n)" and r = "{(ss',ss) . ss <[r] ss'} <*lex*> finite_psubset" in while_rule) \ \Invariant holds initially:\ apply (simp add:stables_def) \ \Invariant is preserved:\ apply(simp add: stables_def split_paired_all) apply(rename_tac ss w) apply(subgoal_tac "(SOME p. p \ w) \ w") prefer 2 apply (fast intro: someI) apply(subgoal_tac "\(q,t) \ set (step (SOME p. p \ w) (ss ! (SOME p. p \ w))). q < length ss \ t \ A") prefer 2 apply clarify apply (rule conjI) apply(clarsimp, blast dest!: boundedD) apply (erule pres_typeD) prefer 3 apply assumption apply (erule listE_nth_in) apply simp apply simp apply (subst decomp_propa) apply fast apply simp apply (rule conjI) apply (rule merges_preserves_type) apply blast apply clarify apply (rule conjI) apply(clarsimp, fast dest!: boundedD) apply (erule pres_typeD) prefer 3 apply assumption apply (erule listE_nth_in) apply blast apply blast apply (rule conjI) apply clarify apply (blast intro!: stable_pres_lemma) apply (rule conjI) apply (blast intro!: merges_incr intro: le_list_trans) apply (rule conjI) apply clarsimp apply (blast intro!: merges_bounded_lemma) apply (blast dest!: boundedD) \ \Postcondition holds upon termination:\ apply(clarsimp simp add: stables_def split_paired_all) \ \Well-foundedness of the termination relation:\ apply (rule wf_lex_prod) apply (insert orderI [THEN acc_le_listI]) apply (simp add: acc_def lesssub_def wfP_wf_eq [symmetric]) apply (rule wf_finite_psubset) \ \Loop decreases along termination relation:\ apply(simp add: stables_def split_paired_all) apply(rename_tac ss w) apply(subgoal_tac "(SOME p. p \ w) \ w") prefer 2 apply (fast intro: someI) apply(subgoal_tac "\(q,t) \ set (step (SOME p. p \ w) (ss ! (SOME p. p \ w))). q < length ss \ t \ A") prefer 2 apply clarify apply (rule conjI) apply(clarsimp, blast dest!: boundedD) apply (erule pres_typeD) prefer 3 apply assumption apply (erule listE_nth_in) apply blast apply blast apply (subst decomp_propa) apply blast apply clarify apply (simp del: listE_length add: lex_prod_def finite_psubset_def bounded_nat_set_is_finite) apply (rule termination_lemma) apply assumption+ defer apply assumption apply clarsimp done qed lemma kildall_properties: assumes semilat: "semilat (A, r, f)" shows "\ acc r; pres_type step n A; mono r step n A; bounded step n; ss0 \ list n A \ \ kildall r f step ss0 \ list n A \ stables r step (kildall r f step ss0) \ ss0 <=[r] kildall r f step ss0 \ (\ts\list n A. ss0 <=[r] ts \ stables r step ts \ kildall r f step ss0 <=[r] ts)" (is "PROP ?P") proof - interpret Semilat A r f using assms by (rule Semilat.intro) show "PROP ?P" -apply (unfold kildall_def) -apply(case_tac "iter f step ss0 (unstables r step ss0)") -apply(simp) -apply (rule iter_properties) -apply (simp_all add: unstables_def stable_def) -apply (rule semilat) -done + apply (unfold kildall_def) + apply(case_tac "iter f step ss0 (unstables r step ss0)") + apply(simp) + apply (rule iter_properties) + apply (simp_all add: unstables_def stable_def) + apply (rule semilat) + done qed lemma is_bcv_kildall: assumes semilat: "semilat (A, r, f)" shows "\ acc r; top r T; pres_type step n A; bounded step n; mono r step n A \ \ is_bcv r T step n A (kildall r f step)" (is "PROP ?P") proof - interpret Semilat A r f using assms by (rule Semilat.intro) show "PROP ?P" apply(unfold is_bcv_def wt_step_def) apply(insert semilat kildall_properties[of A]) apply(simp add:stables_def) apply clarify apply(subgoal_tac "kildall r f step ss \ list n A") prefer 2 apply (simp(no_asm_simp)) apply (rule iffI) apply (rule_tac x = "kildall r f step ss" in bexI) apply (rule conjI) apply (blast) apply (simp (no_asm_simp)) apply(assumption) apply clarify apply(subgoal_tac "kildall r f step ss!p <=_r ts!p") apply simp apply (blast intro!: le_listD less_lengthI) done qed end