Adjust Strengthen, split out ProvePart.

This commit is contained in:
Thomas Sewell 2015-11-10 14:57:20 +11:00
parent 411ef475dc
commit 91ff60c978
4 changed files with 470 additions and 309 deletions

182
lib/ProvePart.thy Normal file
View File

@ -0,0 +1,182 @@
theory ProvePart
imports Main
begin
text {* Introduces a (sort-of) tactic for proving part of a goal by automatic
methods. The split between the proven and unproven part goes down into conjunction,
implication etc. The unproven parts are left in (roughly) their original form. *}
text {*
The first part is to take a goal and split it into two conjuncts,
e.g. "a \<and> (\<forall>x. b \<and> c x)
= (((P1 \<longrightarrow> a) \<and> (\<forall>x. (P2 \<longrightarrow> b) \<and> (P3 \<longrightarrow> c x)))
\<and> ((\<not> P1 \<longrightarrow> a) \<and> (\<forall>x. (\<not> P2 \<longrightarrow> b) \<and> (\<not> P3 \<longrightarrow> c x)))"
The first conjunct is then attacked by some automatic method.
The final part is to eliminate any goals remaining after that
automatic method by setting the Pi to False. The remaining Pi
(whose goal fragments were solved) are set to True. If the
resulting goals cannot be solved by setting to False, or if
no Pi are actually set to true, the process fails.
*}
lemma logic_to_conj_thm_workers:
"A = (A' \<and> A'') \<Longrightarrow> B = (B' \<and> B'')
\<Longrightarrow> (A \<and> B) = ((A' \<and> B') \<and> (A'' \<and> B''))"
"B = (B' \<and> B'')
\<Longrightarrow> (A \<or> B) = ((A \<or> B') \<and> (A \<or> B''))"
"\<lbrakk> \<And>x. P x = (P' x \<and> P'' x) \<rbrakk>
\<Longrightarrow> (\<forall>x. P x) = ((\<forall>x. P' x) \<and> (\<forall>x. P'' x))"
"\<lbrakk> \<And>x. P x = (P' x \<and> P'' x) \<rbrakk>
\<Longrightarrow> (\<forall>x \<in> S. P x) = ((\<forall>x \<in> S. P' x) \<and> (\<forall>x \<in> S. P'' x))"
"B = (B' \<and> B'')
\<Longrightarrow> (A \<longrightarrow> B) = ((A \<longrightarrow> B') \<and> (A \<longrightarrow> B''))"
by auto
ML {*
structure Split_To_Conj = struct
fun abs_name (Abs (s, _, _)) = s
| abs_name _ = "x"
fun all_type (Const (@{const_name "All"}, T) $ _)
= domain_type (domain_type T)
| all_type (Const (@{const_name "Ball"}, T) $ _ $ _)
= domain_type (domain_type (range_type T))
| all_type t = raise TERM ("all_type", [t])
fun split_thm prefix ctxt t = let
val ok = not (String.isPrefix "Q" prefix orelse String.isPrefix "R" prefix)
val _ = ok orelse error ("split_thm: prefix has prefix Q/R: " ^ prefix)
fun params (@{term "op \<and>"} $ x $ y) Ts = params x Ts @ params y Ts
| params (@{term "op \<or>"} $ _ $ y) Ts = (Ts, SOME @{typ bool}) :: params y Ts
| params (all as (Const (@{const_name "All"}, _) $ t)) Ts
= params (betapply (t, Bound 0)) (all_type all :: Ts)
| params (ball as (Const (@{const_name "Ball"}, T) $ _ $ t)) Ts
= (Ts, SOME (domain_type T)) :: params (betapply (t, Bound 0)) (all_type ball :: Ts)
| params (@{term "op \<longrightarrow>"} $ _ $ t) Ts = (Ts, SOME @{typ bool}) :: params t Ts
| params _ Ts = [(Ts, NONE)]
val ps = params t []
val Ps = Variable.variant_frees ctxt [t]
(replicate (length ps) (prefix, @{typ bool}))
|> map Free
val Qs = Variable.variant_frees ctxt [t]
(map (fn (ps, T) => case T of NONE => ("Q", ps ---> @{typ bool})
| SOME T => ("R", ps ---> T)) ps)
|> map Free
val Qs = map (fn (Q, (ps, _)) => Term.list_comb (Q, map Bound (0 upto (length ps - 1))))
(Qs ~~ ps)
fun assemble_bits (@{term "op \<and>"} $ x $ y) Ps = let
val (x, Ps) = assemble_bits x Ps
val (y, Ps) = assemble_bits y Ps
in (@{term "op \<and>"} $ x $ y, Ps) end
| assemble_bits (@{term "op \<or>"} $ _ $ y) Ps = let
val x = hd Ps
val (y, Ps) = assemble_bits y (tl Ps)
in (@{term "op \<or>"} $ x $ y, Ps) end
| assemble_bits (all as (Const (@{const_name "All"}, T) $ t)) Ps = let
val nm = abs_name t
val (t, Ps) = assemble_bits (betapply (t, Bound 0)) Ps
in (Const (@{const_name "All"}, T) $ Abs (nm, all_type all, t), Ps) end
| assemble_bits (ball as (Const (@{const_name "Ball"}, T) $ _ $ t)) Ps = let
val nm = abs_name t
val S = hd Ps
val (t, Ps) = assemble_bits (betapply (t, Bound 0)) (tl Ps)
in (Const (@{const_name "Ball"}, T) $ S $ Abs (nm, all_type ball, t), Ps) end
| assemble_bits (@{term "op \<longrightarrow>"} $ _ $ y) Ps = let
val x = hd Ps
val (y, Ps) = assemble_bits y (tl Ps)
in (@{term "op \<longrightarrow>"} $ x $ y, Ps) end
| assemble_bits _ Ps = (hd Ps, tl Ps)
val bits_lhs = assemble_bits t Qs |> fst
fun imp tf (P, Q) = if String.isPrefix "R" (fst (dest_Free (head_of Q))) then Q
else HOLogic.mk_imp (if tf then P else HOLogic.mk_not P, Q)
val bits_true = assemble_bits t (map (imp true) (Ps ~~ Qs)) |> fst
val bits_false = assemble_bits t (map (imp false) (Ps ~~ Qs)) |> fst
val concl = HOLogic.mk_eq (bits_lhs, HOLogic.mk_conj (bits_true, bits_false))
|> HOLogic.mk_Trueprop
in (Goal.prove ctxt (map (fst o dest_Free o head_of) Qs) [] concl
(K (REPEAT_ALL_NEW (resolve_tac ctxt
@{thms logic_to_conj_thm_workers cases_simp[symmetric]}) 1)),
map dest_Free Ps)
end
fun get_split_tac prefix ctxt tac = SUBGOAL (fn (t, i) =>
let
val concl = HOLogic.dest_Trueprop (Logic.strip_assums_concl t)
val (thm, Ps) = split_thm prefix ctxt concl
in (rtac @{thm iffD2} THEN' rtac thm THEN' tac Ps) end i)
end
*}
text {* Testing. *}
ML {*
Split_To_Conj.split_thm "P" @{context}
@{term "x & y & (\<forall>t \<in> UNIV. \<forall>n. True \<longrightarrow> z t n)"}
*}
ML {*
structure Partial_Prove = struct
fun inst_frees_tac ctxt Ps ct = REPEAT_DETERM o SUBGOAL (fn (t, _) =>
fn thm => case Term.add_frees t [] |> filter (member (op =) Ps)
of [] => Seq.empty
| (f :: _) => let
val idx = Thm.maxidx_of thm + 1
val var = Thm.cterm_of ctxt (Var ((fst f, idx), snd f))
in thm |> Thm.generalize ([], [fst f]) idx
|> Thm.instantiate ([], [(var, ct)])
|> Seq.single
end)
fun cleanup_tac ctxt Ps
= inst_frees_tac ctxt Ps @{cterm False}
THEN' asm_full_simp_tac ctxt
fun finish_tac ctxt Ps = inst_frees_tac ctxt Ps @{cterm True}
THEN' CONVERSION (Conv.concl_conv ~1 (Simplifier.rewrite (put_simpset HOL_ss ctxt)))
fun test_start_partial_prove ctxt i t = let
val j = Thm.nprems_of t - i
in Split_To_Conj.get_split_tac ("P_" ^ string_of_int j ^ "_") ctxt
(K (K all_tac)) i t
end
fun test_end_partial_prove ctxt t = let
fun match_P (s, T) = case space_explode "_" s of
["P", n, _] => try (fn () => ((s, T), the (Int.fromString n))) ()
| _ => NONE
val Ps = Term.add_frees (Thm.concl_of t) [] |> map_filter match_P
fun getmax ((x, n) :: xs) max maxes = if n > max then getmax xs n [x]
else getmax xs max maxes
| getmax [] max maxes = (max, maxes)
val (j, Ps) = getmax Ps 0 []
val i = Thm.nprems_of t - j
in REPEAT_DETERM (FIRSTGOAL (fn k => if k < i then cleanup_tac ctxt Ps k else no_tac))
THEN finish_tac ctxt Ps i end t
fun partial_prove tactic ctxt i
= Split_To_Conj.get_split_tac ("P_" ^ string_of_int i ^ "_") ctxt
(fn Ps => fn i => tactic i THEN finish_tac ctxt Ps i) i
fun method (ctxtg, []) = (fn ctxt => Method.SIMPLE_METHOD (test_start_partial_prove ctxt 1),
(ctxtg, []))
| method args = error "Partial_Prove: still working on that"
fun fin_method () = Scan.succeed (fn ctxt => Method.SIMPLE_METHOD (test_end_partial_prove ctxt))
end
*}
method_setup partial_prove = {* Partial_Prove.method *}
"partially prove a compound goal by some automatic method"
method_setup finish_partial_prove = {* Partial_Prove.fin_method () *}
"partially prove a compound goal by some automatic method"
end

View File

@ -6,26 +6,119 @@ begin
text {* Strengthen *}
definition
"strengthen_imp rel x y = (x = y \<or> rel x y)"
locale strengthen_implementation begin
lemma strengthen_imp_refl:
"strengthen_imp rel x x"
by (simp add: strengthen_imp_def)
definition "st P rel x y = (x = y \<or> (P \<and> rel x y) \<or> (\<not> P \<and> rel y x))"
lemma strengthen_impI:
"rel x y \<Longrightarrow> strengthen_imp rel x y"
by (simp add: strengthen_imp_def)
definition "failed == True"
lemmas imp_to_strengthen = strengthen_impI[where rel="op \<longrightarrow>"]
definition elim :: "prop \<Rightarrow> prop"
where
"elim (P :: prop) == P"
definition "oblig (P :: prop) == P"
end
notation strengthen_implementation.elim ("{elim| _ |}")
notation strengthen_implementation.oblig ("{oblig| _ |}")
notation strengthen_implementation.failed ("<strg-failed>")
syntax
"_ap_strg_bool" :: "['a, 'a] => 'a" ("_ =strg<--|=> _")
"_ap_wkn_bool" :: "['a, 'a] => 'a" ("_ =strg-->|=> _")
"_ap_ge_bool" :: "['a, 'a] => 'a" ("_ =strg<=|=> _")
"_ap_le_bool" :: "['a, 'a] => 'a" ("_ =strg>=|=> _")
syntax(xsymbols)
"_ap_strg_bool" :: "['a, 'a] => 'a" ("_ =strg\<longleftarrow>|=> _")
"_ap_wkn_bool" :: "['a, 'a] => 'a" ("_ =strg\<longrightarrow>|=> _")
"_ap_ge_bool" :: "['a, 'a] => 'a" ("_ =strg\<le>|=> _")
"_ap_le_bool" :: "['a, 'a] => 'a" ("_ =strg\<ge>|=> _")
translations
"P =strg\<longleftarrow>|=> Q" == "CONST strengthen_implementation.st (CONST False) (CONST HOL.implies) P Q"
"P =strg\<longrightarrow>|=> Q" == "CONST strengthen_implementation.st (CONST True) (CONST HOL.implies) P Q"
"P =strg\<le>|=> Q" == "CONST strengthen_implementation.st (CONST False) (CONST Orderings.less_eq) P Q"
"P =strg\<ge>|=> Q" == "CONST strengthen_implementation.st (CONST True) (CONST Orderings.less_eq) P Q"
context strengthen_implementation begin
lemma failedI:
"<strg-failed>"
by (simp add: failed_def)
lemma strengthen_refl:
"st P rel x x"
by (simp add: st_def)
lemma strengthenI:
"rel x y \<Longrightarrow> st True rel x y"
"rel y x \<Longrightarrow> st False rel x y"
by (simp_all add: st_def)
lemmas imp_to_strengthen = strengthenI(2)[where rel="op \<longrightarrow>"]
lemmas rev_imp_to_strengthen = strengthenI(1)[where rel="op \<longrightarrow>"]
lemmas ord_to_strengthen = strengthenI[where rel="op \<le>"]
lemma use_strengthen_imp:
"strengthen_imp (op \<longrightarrow>) P Q \<Longrightarrow> P \<Longrightarrow> Q"
by (simp add: strengthen_imp_def)
"st False (op \<longrightarrow>) Q P \<Longrightarrow> P \<Longrightarrow> Q"
by (simp add: st_def)
lemma strengthen_Not:
"st False rel x y \<Longrightarrow> st (\<not> True) rel x y"
"st True rel x y \<Longrightarrow> st (\<not> False) rel x y"
by auto
lemmas gather =
swap_prems_eq[where A="PROP (Trueprop P)" and B="PROP (elim Q)" for P Q]
swap_prems_eq[where A="PROP (Trueprop P)" and B="PROP (oblig Q)" for P Q]
lemma mk_True_imp:
"P \<equiv> True \<longrightarrow> P"
by simp
lemma narrow_quant:
"(\<And>x. PROP P \<Longrightarrow> PROP (Q x)) \<equiv> (PROP P \<Longrightarrow> (\<And>x. PROP (Q x)))"
"(\<And>x. (R \<longrightarrow> S x)) \<equiv> PROP (Trueprop (R \<longrightarrow> (\<forall>x. S x)))"
"(\<And>x. (S x \<longrightarrow> R)) \<equiv> PROP (Trueprop ((\<exists>x. S x) \<longrightarrow> R))"
apply (simp_all add: atomize_all)
apply rule
apply assumption
apply assumption
done
ML {*
structure Make_Strengthen_Rule = struct
fun binop_conv' cv1 cv2 = Conv.combination_conv (Conv.arg_conv cv1) cv2;
val mk_elim = Conv.rewr_conv @{thm elim_def[symmetric]}
val mk_oblig = Conv.rewr_conv @{thm oblig_def[symmetric]}
fun count_vars t = Term.fold_aterms
(fn (Var v) => Termtab.map_default (Var v, 0) (fn x => x + 1)
| _ => I) t Termtab.empty
fun gather_to_imp ctxt drule pattern = let
val pattern = (if drule then "D" :: pattern else pattern)
fun inner pat ct = case (head_of (Thm.term_of ct), pat) of
(@{term Pure.imp}, ("E" :: pat)) => binop_conv' mk_elim (inner pat) ct
| (@{term Pure.imp}, ("O" :: pat)) => binop_conv' mk_oblig (inner pat) ct
| (@{term Pure.imp}, _) => binop_conv' (Object_Logic.atomize ctxt) (inner (drop 1 pat)) ct
| (_, []) => Object_Logic.atomize ctxt ct
| (_, pat) => raise THM ("gather_to_imp: leftover pattern: " ^ commas pat, 1, [])
fun simp thms = Raw_Simplifier.rewrite ctxt false thms
fun ensure_imp ct = case (strip_comb (Thm.term_of ct) |> apsnd (map head_of)) of
(@{term Pure.imp}, []) => Conv.arg_conv ensure_imp ct
| (@{term HOL.Trueprop}, [@{term HOL.implies}]) => Conv.all_conv ct
| _ => Conv.rewr_conv @{thm mk_True_imp} ct
val gather = simp @{thms gather}
then_conv (if drule then Conv.all_conv else simp @{thms atomize_conjL})
then_conv simp @{thms atomize_imp}
then_conv ensure_imp
in Conv.fconv_rule (inner pattern then_conv gather) end
fun imp_list t = let
val (x, y) = Logic.dest_implies t
in x :: imp_list y end handle TERM _ => [t]
@ -33,55 +126,74 @@ fun imp_list t = let
fun mk_ex (xnm, T) t = HOLogic.exists_const T $ Term.lambda (Var (xnm, T)) t
fun mk_all (xnm, T) t = HOLogic.all_const T $ Term.lambda (Var (xnm, T)) t
fun do_mk ctxt thm = let
val atomize = Object_Logic.atomize_prems ctxt (Thm.cprop_of thm)
val thm2 = Thm.equal_elim atomize thm
val xs = imp_list (Thm.term_of (Thm.rhs_of atomize))
val xs = map HOLogic.dest_Trueprop xs
handle TERM _ => raise TERM ("Make_Strengthen_Rule.mk: Trueprop", xs)
val (concl :: rev_prems) = rev xs
val prem = fold (curry HOLogic.mk_conj) (rev rev_prems) @{term True}
val free_concl = Term.add_vars concl []
val free_prem = Term.add_vars prem []
val ord = prod_ord Term_Ord.indexname_ord Term_Ord.typ_ord
val ex_free_prem = Ord_List.subtract ord (Ord_List.make ord free_concl)
(Ord_List.make ord free_prem)
val ex_prem = fold mk_ex ex_free_prem prem
val imp = (@{term "strengthen_imp (op -->)"}
$ ex_prem $ concl)
val rule = @{term Trueprop} $ fold mk_all free_concl imp |> Thm.cterm_of ctxt
in Goal.prove_internal ctxt [] rule
(K (
REPEAT_DETERM (rtac @{thm allI} 1)
THEN rtac @{thm strengthen_impI} 1
THEN rtac @{thm impI} 1
THEN (REPEAT_DETERM (etac @{thm exE} 1))
THEN rtac thm2 1
THEN ALLGOALS (fn i => REPEAT_DETERM_N (length xs - i - 1) (dtac @{thm conjunct2} i))
THEN ALLGOALS (dtac @{thm conjunct1})
THEN ALLGOALS atac
))
|> Object_Logic.rulify ctxt
fun quantify_vars ctxt drule thm = let
val (lhs, rhs) = Thm.concl_of thm |> HOLogic.dest_Trueprop
|> HOLogic.dest_imp
val all_vars = count_vars (Thm.prop_of thm)
val new_vars = count_vars (if drule then rhs else lhs)
val quant = filter (fn v => Termtab.lookup new_vars v = Termtab.lookup all_vars v)
(Termtab.keys new_vars)
|> map (Thm.cterm_of ctxt)
in fold Thm.forall_intr quant thm
|> Conv.fconv_rule (Raw_Simplifier.rewrite ctxt false @{thms narrow_quant})
end
fun mk_thm ctxt thm = (HOLogic.dest_Trueprop (Thm.prop_of thm);
thm RS @{thm imp_to_strengthen})
handle TERM _ => do_mk ctxt thm
handle THM _ => raise THM ("Make_Strengthen_Rule.mk_thm:"
^ " not impl or meta-impl", 1, [thm])
fun mk_strg (typ, pat) ctxt thm = let
val drule = typ = "D" orelse typ = "D'"
val imp = gather_to_imp ctxt drule pat thm
|> (if typ = "I'" orelse typ = "D'"
then quantify_vars ctxt drule else I)
in if typ = "I" orelse typ = "I'"
then imp RS @{thm imp_to_strengthen}
else if drule then imp RS @{thm rev_imp_to_strengthen}
else if typ = "lhs" then imp RS @{thm ord_to_strengthen(1)}
else if typ = "rhs" then imp RS @{thm ord_to_strengthen(2)}
else raise THM ("mk_strg: unknown type: " ^ typ, 1, [thm])
end
fun auto_mk ctxt thm = let
val concl_C = try (fst o dest_Const o head_of
o HOLogic.dest_Trueprop) (Thm.concl_of thm)
in case (Thm.nprems_of thm, concl_C) of
(_, SOME @{const_name failed}) => thm
| (_, SOME @{const_name st}) => thm
| (0, SOME @{const_name HOL.implies}) => (thm RS @{thm imp_to_strengthen}
handle THM _ => @{thm failedI})
| _ => mk_strg ("I'", []) ctxt thm
end
fun mk_strg_args (SOME (typ, pat)) ctxt thm = mk_strg (typ, pat) ctxt thm
| mk_strg_args NONE ctxt thm = auto_mk ctxt thm
val arg_pars = Scan.option (Scan.first (map Args.$$$ ["I", "I'", "D", "D'", "lhs", "rhs"])
-- Scan.repeat (Args.$$$ "E" || Args.$$$ "O" || Args.$$$ "_"))
val setup =
Attrib.setup @{binding "mk_strg"}
((Scan.lift arg_pars -- Args.context)
>> (fn (args, ctxt) => Thm.rule_attribute (K (mk_strg_args args ctxt))))
"put rule in 'strengthen' form"
end
*}
ML {*
Make_Strengthen_Rule.mk_thm @{context} @{thm nat.induct}
*}
end
context strengthen_implementation begin
lemma do_elim:
"PROP P \<Longrightarrow> PROP elim (PROP P)"
by (simp add: elim_def)
lemma intro_oblig:
"PROP P \<Longrightarrow> PROP oblig (PROP P)"
by (simp add: oblig_def)
ML {*
structure Strengthen = struct
structure Congs = Generic_Data
structure Congs = Theory_Data
(struct
type T = thm list
val empty = []
@ -89,38 +201,49 @@ structure Congs = Generic_Data
val merge = Thm.merge_thms;
end);
fun map_context_total f (Context.Theory t) = (Context.Theory (f t))
| map_context_total f (Context.Proof p)
= (Context.Proof (Context.raw_transfer (f (Proof_Context.theory_of p)) p))
val strg_add = Thm.declaration_attribute
(fn thm =>
(Congs.map (Thm.add_thm thm)));
(fn thm => map_context_total (Congs.map (Thm.add_thm thm)));
val strg_del = Thm.declaration_attribute
(fn thm =>
(Congs.map (Thm.del_thm thm)));
(fn thm => map_context_total (Congs.map (Thm.del_thm thm)));
val setup =
Attrib.setup @{binding "strg"} (Attrib.add_del strg_add strg_del)
"strengthening congruence rules";
infix 1 THEN_ALL_NEW_SOLVED;
val do_elim = SUBGOAL (fn (t, i) => case (head_of (Logic.strip_assums_concl t)) of
@{term elim} => etac @{thm do_elim} i
| _ => all_tac)
(* Like THEN_ALL_NEW but insists at least one goal is solved
by the various applications of tac2. *)
fun (tac1 THEN_ALL_NEW_SOLVED tac2) i st =
st |> (tac1 i THEN SOLVED' (fn _ => fn st' =>
Seq.INTERVAL tac2 i (i + Thm.nprems_of st' - Thm.nprems_of st) st') 52);
infix 1 THEN_TRY_ALL_NEW;
(* Like THEN_ALL_NEW but allows failure, although at least one subsequent
method must succeed. *)
fun (tac1 THEN_TRY_ALL_NEW tac2) i st = let
fun inner b j st = if i > j then (if b then all_tac else no_tac) st
else ((tac2 j THEN inner true (j - 1)) ORELSE inner b (j - 1)) st
in st |> (tac1 i THEN (fn st' =>
inner false (i + Thm.nprems_of st' - Thm.nprems_of st) st')) end
fun apply_strg ctxt congs rules = let
in resolve_tac ctxt rules
ORELSE' ((resolve_tac ctxt congs
THEN_ALL_NEW_SOLVED (fn i => TRY (apply_strg ctxt congs rules i)))
THEN_ALL_NEW rtac @{thm strengthen_imp_refl})
in TRY o resolve_tac ctxt @{thms strengthen_Not}
THEN' ((resolve_tac ctxt rules THEN_ALL_NEW do_elim)
ORELSE' (resolve_tac ctxt congs THEN_TRY_ALL_NEW (fn i => apply_strg ctxt congs rules i)))
end
fun do_strg ctxt congs rules
= apply_strg ctxt congs rules
THEN_ALL_NEW (TRY o resolve_tac ctxt @{thms strengthen_refl intro_oblig})
fun strengthen ctxt thms = let
val congs = Congs.get (Context.Proof ctxt)
val rules = map (Make_Strengthen_Rule.mk_thm ctxt) thms
val congs = Congs.get (Proof_Context.theory_of ctxt)
val rules = map (Make_Strengthen_Rule.auto_mk ctxt) thms
in rtac @{thm use_strengthen_imp}
THEN' apply_strg ctxt congs rules end
THEN' do_strg ctxt congs rules end
val strengthen_args =
Attrib.thms >> curry (fn (rules, ctxt) =>
@ -133,6 +256,8 @@ end
*}
end
setup "Strengthen.setup"
method_setup strengthen = {* Strengthen.strengthen_args *}
@ -140,142 +265,96 @@ method_setup strengthen = {* Strengthen.strengthen_args *}
text {* Important strengthen congruence rules. *}
lemma strengthen_imp_imp:
"strengthen_imp (op \<longrightarrow>) A B = (A \<longrightarrow> B)"
"strengthen_imp (swp (op \<longrightarrow>)) A B = (B \<longrightarrow> A)"
by (simp_all add: strengthen_imp_def swp_def)
context strengthen_implementation begin
context begin
lemma strengthen_imp_imp[simp]:
"st True (op \<longrightarrow>) A B = (A \<longrightarrow> B)"
"st False (op \<longrightarrow>) A B = (B \<longrightarrow> A)"
by (simp_all add: st_def)
private abbreviation(input)
"stimp_ord a \<equiv> strengthen_imp (op \<le>) (a :: 'a :: preorder)"
private abbreviation(input)
"stimp_ord2 a \<equiv> strengthen_imp (swp (op \<le>)) (a :: 'a :: preorder)"
abbreviation(input)
"st_ord t \<equiv> st t (op \<le> :: ('a :: preorder) \<Rightarrow> _)"
lemma strengthen_imp_ord:
"stimp_ord A B = (A \<le> B)"
"stimp_ord2 A B = (B \<le> A)"
by (auto simp add: strengthen_imp_def swp_def)
private declare strengthen_imp_ord[simp]
private declare strengthen_imp_imp[simp]
lemma strengthen_imp_ord[simp]:
"st_ord True A B = (A \<le> B)"
"st_ord False A B = (B \<le> A)"
by (auto simp add: st_def)
lemma strengthen_imp_conj [strg]:
"\<lbrakk> strengthen_imp (op \<longrightarrow>) A A'; strengthen_imp (op \<longrightarrow>) B B' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (A \<and> B) (A' \<and> B')"
by (simp add: strengthen_imp_imp)
lemma strengthen_imp_conj2 [strg]:
"\<lbrakk> strengthen_imp (swp (op \<longrightarrow>)) A A'; strengthen_imp (swp (op \<longrightarrow>)) B B' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (A \<and> B) (A' \<and> B')"
by simp
"\<lbrakk> B \<Longrightarrow> st F (op \<longrightarrow>) A A'; A' \<Longrightarrow> st F (op \<longrightarrow>) B B' \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (A \<and> B) (A' \<and> B')"
by (cases F, auto)
lemma strengthen_imp_disj [strg]:
"\<lbrakk> strengthen_imp (op \<longrightarrow>) A A'; strengthen_imp (op \<longrightarrow>) B B' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (A \<or> B) (A' \<or> B')"
by simp
"\<lbrakk> \<not> B \<Longrightarrow> st F (op \<longrightarrow>) A A'; \<not> A' \<Longrightarrow> st F (op \<longrightarrow>) B B' \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (A \<or> B) (A' \<or> B')"
by (cases F, auto)
lemma strengthen_imp_disj2 [strg]:
"\<lbrakk> strengthen_imp (swp (op \<longrightarrow>)) A A'; strengthen_imp (swp (op \<longrightarrow>)) B B' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (A \<or> B) (A' \<or> B')"
by simp
lemma strengthen_imp [strg]:
"\<lbrakk> strengthen_imp (swp (op \<longrightarrow>)) X X'; strengthen_imp (op \<longrightarrow>) Y Y' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (X \<longrightarrow> Y) (X' \<longrightarrow> Y')"
by simp
lemma strengthen_imp2 [strg]:
"\<lbrakk> strengthen_imp (op \<longrightarrow>) X X'; strengthen_imp (swp (op \<longrightarrow>)) Y Y' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (X \<longrightarrow> Y) (X' \<longrightarrow> Y')"
by simp
lemma strengthen_imp_implies [strg]:
"\<lbrakk> st (\<not> F) (op \<longrightarrow>) X X'; X' \<Longrightarrow> st F (op \<longrightarrow>) Y Y' \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (X \<longrightarrow> Y) (X' \<longrightarrow> Y')"
by (cases F, auto)
lemma strengthen_all[strg]:
"\<lbrakk> \<And>x. strengthen_imp (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<forall>x. P x) (\<forall>x. Q x)"
by auto
lemma strengthen_all2[strg]:
"\<lbrakk> \<And>x. strengthen_imp (swp (op \<longrightarrow>)) (P x) (Q x) \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (\<forall>x. P x) (\<forall>x. Q x)"
by auto
"\<lbrakk> \<And>x. st F (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (\<forall>x. P x) (\<forall>x. Q x)"
by (cases F, auto)
lemma strengthen_ex[strg]:
"\<lbrakk> \<And>x. strengthen_imp (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<exists>x. P x) (\<exists>x. Q x)"
by auto
lemma strengthen_ex2[strg]:
"\<lbrakk> \<And>x. strengthen_imp (swp (op \<longrightarrow>)) (P x) (Q x) \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (\<exists>x. P x) (\<exists>x. Q x)"
by auto
"\<lbrakk> \<And>x. st F (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (\<exists>x. P x) (\<exists>x. Q x)"
by (cases F, auto)
lemma strengthen_Ball[strg]:
"\<lbrakk> \<And>x. strengthen_imp (op \<longrightarrow>) (P x) (Q x);
stimp_ord2 S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<forall>x \<in> S. P x) (\<forall>x \<in> S. Q x)"
by auto
lemma strengthen_Ball2[strg]:
"\<lbrakk> \<And>x. strengthen_imp (swp (op \<longrightarrow>)) (P x) (Q x);
stimp_ord S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (\<forall>x \<in> S. P x) (\<forall>x \<in> S'. Q x)"
by auto
"\<lbrakk> st_ord (Not F) S S';
\<And>x. x \<in> S' \<Longrightarrow> st F (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (\<forall>x \<in> S. P x) (\<forall>x \<in> S'. Q x)"
by (cases F, auto)
lemma strengthen_Bex[strg]:
"\<lbrakk> \<And>x. strengthen_imp (op \<longrightarrow>) (P x) (Q x);
stimp_ord2 S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<exists>x \<in> S. P x) (\<exists>x \<in> S. Q x)"
by auto
lemma strengthen_Bex2[strg]:
"\<lbrakk> \<And>x. strengthen_imp (swp (op \<longrightarrow>)) (P x) (Q x);
stimp_ord S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (\<exists>x \<in> S. P x) (\<exists>x \<in> S. Q x)"
by auto
"\<lbrakk> st_ord F S S';
\<And>x. x \<in> S' \<Longrightarrow> st F (op \<longrightarrow>) (P x) (Q x) \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (\<exists>x \<in> S. P x) (\<exists>x \<in> S'. Q x)"
by (cases F, auto)
lemma strengthen_Collect[strg]:
"\<lbrakk> \<And>x. strengthen_imp (op \<longrightarrow>) (P x) (P' x) \<rbrakk>
\<Longrightarrow> stimp_ord {x. P x} {x. P' x}"
by auto
lemma strengthen_Collect2[strg]:
"\<lbrakk> \<And>x. strengthen_imp (swp (op \<longrightarrow>)) (P x) (P' x) \<rbrakk>
\<Longrightarrow> stimp_ord2 {x. P x} {x. P' x}"
by auto
"\<lbrakk> \<And>x. st F (op \<longrightarrow>) (P x) (P' x) \<rbrakk>
\<Longrightarrow> st_ord F {x. P x} {x. P' x}"
by (cases F, auto)
lemma strengthen_mem[strg]:
"\<lbrakk> strengthen_imp (op \<le>) S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (x \<in> S) (x \<in> S')"
by auto
lemma strengthen_mem2[strg]:
"\<lbrakk> strengthen_imp (swp (op \<le>)) S S' \<rbrakk>
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (x \<in> S) (x \<in> S')"
by auto
"\<lbrakk> st_ord F S S' \<rbrakk>
\<Longrightarrow> st F (op \<longrightarrow>) (x \<in> S) (x \<in> S')"
by (cases F, auto)
lemma strengthen_ord[strg]:
"stimp_ord2 x x' \<Longrightarrow> stimp_ord y y'
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (x \<le> y) (x' \<le> y')"
by (simp, metis order_trans)
lemma strengthen_ord2[strg]:
"stimp_ord x x' \<Longrightarrow> stimp_ord2 y y'
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (x \<le> y) (x' \<le> y')"
by (simp, metis order_trans)
"st_ord (\<not> F) x x' \<Longrightarrow> st_ord F y y'
\<Longrightarrow> st F (op \<longrightarrow>) (x \<le> y) (x' \<le> y')"
by (cases F, simp_all, (metis order_trans)+)
lemma strengthen_strict_ord[strg]:
"stimp_ord2 x x' \<Longrightarrow> stimp_ord y y'
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (x < y) (x' < y')"
by (simp, metis order_le_less_trans order_less_le_trans)
"st_ord (\<not> F) x x' \<Longrightarrow> st_ord F y y'
\<Longrightarrow> st F (op \<longrightarrow>) (x < y) (x' < y')"
by (cases F, simp_all, (metis order_le_less_trans order_less_le_trans)+)
lemma strengthen_strict_ord2[strg]:
"stimp_ord x x' \<Longrightarrow> stimp_ord2 y y'
\<Longrightarrow> strengthen_imp (swp (op \<longrightarrow>)) (x < y) (x' < y')"
by (simp, metis order_le_less_trans order_less_le_trans)
lemma strengthen_image[strg]:
"st_ord F S S' \<Longrightarrow> st_ord F (f ` S) (f ` S')"
by (cases F, auto)
(* FIXME: add image, revimage, restrict_map, Int, Un, all variants
of big set UN/INT syntax, all relevant order stuff, etc. *)
lemma strengthen_vimage[strg]:
"st_ord F S S' \<Longrightarrow> st_ord F (f -` S) (f -` S')"
by (cases F, auto)
lemma strengthen_Int[strg]:
"st_ord F A A' \<Longrightarrow> st_ord F B B' \<Longrightarrow> st_ord F (A \<inter> B) (A' \<inter> B')"
by (cases F, auto)
lemma strengthen_Un[strg]:
"st_ord F A A' \<Longrightarrow> st_ord F B B' \<Longrightarrow> st_ord F (A \<union> B) (A' \<union> B')"
by (cases F, auto)
(* FIXME: add all variants
of big set UN/INT syntax, maps, all relevant order stuff, etc. *)
lemma imp_consequent:
"P \<longrightarrow> Q \<longrightarrow> P" by simp

View File

@ -2141,25 +2141,29 @@ lemma validE_NF_condition [wp]:
text {* Strengthen setup. *}
context strengthen_implementation begin
lemma strengthen_hoare [strg]:
"(\<And>r s. strengthen_imp (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>)"
by (auto elim: hoare_strengthen_post)
"(\<And>r s. st F (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> st F (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>)"
by (cases F, auto elim: hoare_strengthen_post)
lemma strengthen_validE_R_cong[strg]:
"(\<And>r s. strengthen_imp (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, -) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>, -)"
by (auto intro: hoare_post_imp_R)
"(\<And>r s. st F (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> st F (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, -) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>, -)"
by (cases F, auto intro: hoare_post_imp_R)
lemma strengthen_validE_cong[strg]:
"(\<And>r s. strengthen_imp (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> (\<And>r s. strengthen_imp (op \<longrightarrow>) (S r s) (T r s))
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>S\<rbrace>) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>, \<lbrace>T\<rbrace>)"
by (auto elim: hoare_post_impErr)
"(\<And>r s. st F (op \<longrightarrow>) (Q r s) (R r s))
\<Longrightarrow> (\<And>r s. st F (op \<longrightarrow>) (S r s) (T r s))
\<Longrightarrow> st F (op \<longrightarrow>) (\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>S\<rbrace>) (\<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>, \<lbrace>T\<rbrace>)"
by (cases F, auto elim: hoare_post_impErr)
lemma strengthen_validE_E_cong[strg]:
"(\<And>r s. strengthen_imp (op \<longrightarrow>) (S r s) (T r s))
\<Longrightarrow> strengthen_imp (op \<longrightarrow>) (\<lbrace>P\<rbrace> f -, \<lbrace>S\<rbrace>) (\<lbrace>P\<rbrace> f -, \<lbrace>T\<rbrace>)"
by (auto elim: hoare_post_impErr simp: validE_E_def)
"(\<And>r s. st F (op \<longrightarrow>) (S r s) (T r s))
\<Longrightarrow> st F (op \<longrightarrow>) (\<lbrace>P\<rbrace> f -, \<lbrace>S\<rbrace>) (\<lbrace>P\<rbrace> f -, \<lbrace>T\<rbrace>)"
by (cases F, auto elim: hoare_post_impErr simp: validE_E_def)
end
end

View File

@ -1,120 +1,17 @@
theory WPBang
imports WP "../Strengthen" NonDetMonadVCG
imports WP "../ProvePart" NonDetMonadVCG
begin
text {*
Splitting up predicates in a particular way.
*}
lemma logic_to_conj_thm_workers:
"A = (A' \<and> A'') \<Longrightarrow> B = (B' \<and> B'')
\<Longrightarrow> (A \<and> B) = ((A' \<and> B') \<and> (A'' \<and> B''))"
"B = (B' \<and> B'')
\<Longrightarrow> (A \<or> B) = ((A \<or> B') \<and> (A \<or> B''))"
"\<lbrakk> \<And>x. P x = (P' x \<and> P'' x) \<rbrakk>
\<Longrightarrow> (\<forall>x. P x) = ((\<forall>x. P' x) \<and> (\<forall>x. P'' x))"
"\<lbrakk> \<And>x. P x = (P' x \<and> P'' x) \<rbrakk>
\<Longrightarrow> (\<forall>x \<in> S. P x) = ((\<forall>x \<in> S. P' x) \<and> (\<forall>x \<in> S. P'' x))"
"B = (B' \<and> B'')
\<Longrightarrow> (A \<longrightarrow> B) = ((A \<longrightarrow> B') \<and> (A \<longrightarrow> B''))"
by auto
ML {*
structure Split_To_Conj = struct
(* Split a composite predicate into two, see test example below. *)
fun abs_name (Abs (s, _, _)) = s
| abs_name _ = "x"
fun all_type (Const (@{const_name "All"}, T) $ _)
= domain_type (domain_type T)
| all_type (Const (@{const_name "Ball"}, T) $ _ $ _)
= domain_type (domain_type (range_type T))
| all_type t = raise TERM ("all_type", [t])
fun split_thm ctxt t = let
fun params (@{term "op \<and>"} $ x $ y) Ts = params x Ts @ params y Ts
| params (@{term "op \<or>"} $ _ $ y) Ts = (Ts, SOME @{typ bool}) :: params y Ts
| params (all as (Const (@{const_name "All"}, _) $ t)) Ts
= params (betapply (t, Bound 0)) (all_type all :: Ts)
| params (ball as (Const (@{const_name "Ball"}, T) $ _ $ t)) Ts
= (Ts, SOME (domain_type T)) :: params (betapply (t, Bound 0)) (all_type ball :: Ts)
| params (@{term "op \<longrightarrow>"} $ _ $ t) Ts = (Ts, SOME @{typ bool}) :: params t Ts
| params _ Ts = [(Ts, NONE)]
val ps = params t []
val Ps = Variable.variant_frees ctxt [t]
(replicate (length ps) ("P", @{typ bool}))
|> map Free
val Qs = Variable.variant_frees ctxt [t]
(map (fn (ps, T) => case T of NONE => ("Q", ps ---> @{typ bool})
| SOME T => ("R", ps ---> T)) ps)
|> map Free
val Qs = map (fn (Q, (ps, _)) => Term.list_comb (Q, map Bound (0 upto (length ps - 1))))
(Qs ~~ ps)
fun assemble_bits (@{term "op \<and>"} $ x $ y) Ps = let
val (x, Ps) = assemble_bits x Ps
val (y, Ps) = assemble_bits y Ps
in (@{term "op \<and>"} $ x $ y, Ps) end
| assemble_bits (@{term "op \<or>"} $ _ $ y) Ps = let
val x = hd Ps
val (y, Ps) = assemble_bits y (tl Ps)
in (@{term "op \<or>"} $ x $ y, Ps) end
| assemble_bits (all as (Const (@{const_name "All"}, T) $ t)) Ps = let
val nm = abs_name t
val (t, Ps) = assemble_bits (betapply (t, Bound 0)) Ps
in (Const (@{const_name "All"}, T) $ Abs (nm, all_type all, t), Ps) end
| assemble_bits (ball as (Const (@{const_name "Ball"}, T) $ _ $ t)) Ps = let
val nm = abs_name t
val S = hd Ps
val (t, Ps) = assemble_bits (betapply (t, Bound 0)) (tl Ps)
in (Const (@{const_name "Ball"}, T) $ S $ Abs (nm, all_type ball, t), Ps) end
| assemble_bits (@{term "op \<longrightarrow>"} $ _ $ y) Ps = let
val x = hd Ps
val (y, Ps) = assemble_bits y (tl Ps)
in (@{term "op \<longrightarrow>"} $ x $ y, Ps) end
| assemble_bits _ Ps = (hd Ps, tl Ps)
val bits_lhs = assemble_bits t Qs |> fst
fun imp tf (P, Q) = if String.isPrefix "R" (fst (dest_Free (head_of Q))) then Q
else HOLogic.mk_imp (if tf then P else HOLogic.mk_not P, Q)
val bits_true = assemble_bits t (map (imp true) (Ps ~~ Qs)) |> fst
val bits_false = assemble_bits t (map (imp false) (Ps ~~ Qs)) |> fst
val concl = HOLogic.mk_eq (bits_lhs, HOLogic.mk_conj (bits_true, bits_false))
|> HOLogic.mk_Trueprop
in Goal.prove ctxt (map (fst o dest_Free o head_of) Qs) [] concl
(K (REPEAT_ALL_NEW (resolve_tac ctxt
@{thms logic_to_conj_thm_workers cases_simp[symmetric]}) 1))
end
end
*}
text {* Testing the split. *}
ML {*
Split_To_Conj.split_thm @{context}
@{term "x & y & (\<forall>t \<in> UNIV. \<forall>n. True \<longrightarrow> z t n)"}
*}
lemma conj_prove_lhsE:
"P \<and> Q \<Longrightarrow> (P \<Longrightarrow> P') \<Longrightarrow> P' \<and> Q"
lemma conj_meta_forward:
"P \<and> Q \<Longrightarrow> (P \<Longrightarrow> P') \<Longrightarrow> (Q \<Longrightarrow> Q') \<Longrightarrow> P' \<and> Q'"
by simp
text {* Applying safe WP rules. *}
ML {*
structure WP_Safe = struct
fun inst_frees_tac ctxt Ps ct = REPEAT_DETERM o SUBGOAL (fn (t, _) =>
fn thm => case Term.add_frees t [] |> filter (member (op =) Ps)
of [] => Seq.empty
| (f :: _) => let
val idx = Thm.maxidx_of thm + 1
val var = Thm.cterm_of ctxt (Var ((fst f, idx), snd f))
in thm |> Thm.generalize ([], [fst f]) idx
|> Thm.instantiate ([], [(var, ct)])
|> Seq.single
end)
fun check_has_frees_tac Ps (_ : int) thm = let
val fs = Term.add_frees (Thm.prop_of thm) [] |> filter (member (op =) Ps)
in if null fs then Seq.empty else Seq.single thm end
@ -125,19 +22,13 @@ fun wp_bang wp_safe_rules ctxt = let
|> map (rotate_prems 1)
in
resolve_tac ctxt wp_safe_rules_conj
THEN' SUBGOAL (fn (t, i) => let
val eq_to_conj_thm = Split_To_Conj.split_thm ctxt
(HOLogic.dest_Trueprop (Logic.strip_assums_concl t))
val Ps = Term.add_frees (Thm.prop_of eq_to_conj_thm) []
in rtac @{thm iffD2} i THEN rtac eq_to_conj_thm i
THEN etac @{thm conj_prove_lhsE} i
THEN (REPEAT_ALL_NEW ((CHANGED o asm_full_simp_tac ctxt) ORELSE' Classical.safe_steps_tac ctxt)
THEN_ALL_NEW inst_frees_tac ctxt Ps @{cterm "False"}
THEN_ALL_NEW (check_has_frees_tac Ps THEN' asm_full_simp_tac ctxt)
) i
THEN inst_frees_tac ctxt Ps @{cterm "True"} i
THEN simp_tac ctxt i
end)
THEN' Split_To_Conj.get_split_tac "P" ctxt
(fn Ps => fn i => etac @{thm conj_meta_forward} i
THEN (REPEAT_ALL_NEW ((CHANGED o asm_full_simp_tac ctxt)
ORELSE' Classical.safe_steps_tac ctxt)
THEN_ALL_NEW Partial_Prove.cleanup_tac ctxt Ps) i
THEN (Partial_Prove.finish_tac ctxt Ps THEN' atac) i
)
end
val wpe_args =
@ -154,7 +45,8 @@ method_setup wpe = {* WP_Safe.wpe_args *}
"applies 'safe' wp rules to eliminate postcondition components"
text {* Testing. *}
lemma
lemma
assumes x: "\<lbrace> P \<rbrace> f \<lbrace> \<lambda>rv. Q \<rbrace>"
and y: "\<lbrace> P \<rbrace> f \<lbrace> \<lambda>rv. R \<rbrace>"
shows
@ -162,6 +54,10 @@ lemma
\<and> (snd rv = Some y \<longrightarrow> Q s )
\<and> R s \<rbrace>"
apply (rule hoare_pre)
apply (simp add: all_conj_distrib)
apply (rule hoare_vcg_conj_lift)
apply (wpe x)
apply wp
apply (wpe x)
apply (wp y)
apply simp