diff --git a/thys/Constructive_Cryptography/More_CryptHOL.thy b/thys/Constructive_Cryptography/More_CryptHOL.thy --- a/thys/Constructive_Cryptography/More_CryptHOL.thy +++ b/thys/Constructive_Cryptography/More_CryptHOL.thy @@ -1,2451 +1,2451 @@ (* Author: Andreas Lochbihler, ETH Zurich *) theory More_CryptHOL imports CryptHOL.CryptHOL begin (* Misc *) lemma is_empty_image [simp]: "Set.is_empty (f ` A) = Set.is_empty A" by(auto simp add: Set.is_empty_def) lemma inj_on_map_sum [simp]: "\ inj_on f A; inj_on g B \ \ inj_on (map_sum f g) (A <+> B)" proof(rule inj_onI, goal_cases) case (1 x y) then show ?case by(cases x; cases y; auto simp add: inj_on_def) qed lemma inv_into_map_sum: "inv_into (A <+> B) (map_sum f g) x = map_sum (inv_into A f) (inv_into B g) x" if "x \ f ` A <+> g ` B" "inj_on f A" "inj_on g B" using that by(cases rule: PlusE[consumes 1])(auto simp add: inv_into_f_eq f_inv_into_f) lemma Pair_fst_Unity: "(fst x, ()) = x" by(cases x) simp fun rsuml :: "('a + 'b) + 'c \ 'a + ('b + 'c)" where "rsuml (Inl (Inl a)) = Inl a" | "rsuml (Inl (Inr b)) = Inr (Inl b)" | "rsuml (Inr c) = Inr (Inr c)" fun lsumr :: "'a + ('b + 'c) \ ('a + 'b) + 'c" where "lsumr (Inl a) = Inl (Inl a)" | "lsumr (Inr (Inl b)) = Inl (Inr b)" | "lsumr (Inr (Inr c)) = Inr c" lemma rsuml_lsumr [simp]: "rsuml (lsumr x) = x" by(cases x rule: lsumr.cases) simp_all lemma lsumr_rsuml [simp]: "lsumr (rsuml x) = x" by(cases x rule: rsuml.cases) simp_all definition rprodl :: "('a \ 'b) \ 'c \ 'a \ ('b \ 'c)" where "rprodl = (\((a, b), c). (a, (b, c)))" lemma rprodl_simps [simp]: "rprodl ((a, b), c) = (a, (b, c))" by(simp add: rprodl_def) lemma rprodl_parametric [transfer_rule]: includes lifting_syntax shows "(rel_prod (rel_prod A B) C ===> rel_prod A (rel_prod B C)) rprodl rprodl" unfolding rprodl_def by transfer_prover definition lprodr :: "'a \ ('b \ 'c) \ ('a \ 'b) \ 'c" where "lprodr = (\(a, b, c). ((a, b), c))" lemma lprodr_simps [simp]: "lprodr (a, b, c) = ((a, b), c)" by(simp add: lprodr_def) lemma lprodr_parametric [transfer_rule]: includes lifting_syntax shows "(rel_prod A (rel_prod B C) ===> rel_prod (rel_prod A B) C) lprodr lprodr" unfolding lprodr_def by transfer_prover lemma lprodr_inverse [simp]: "rprodl (lprodr x) = x" by(cases x) auto lemma rprodl_inverse [simp]: "lprodr (rprodl x) = x" by(cases x) auto lemma rel_fun_comp: "\f g h. rel_fun A B (f \ g) h = rel_fun A (\x. B (f x)) g h" "\f g h. rel_fun A B f (g \ h) = rel_fun A (\x y. B x (g y)) f h" by(auto simp add: rel_fun_def) lemma rel_fun_map_fun1: "rel_fun (BNF_Def.Grp UNIV h)\\ A f g \ rel_fun (=) A (map_fun h id f) g" by(auto simp add: rel_fun_def Grp_def) lemma rel_fun_map_fun2: "rel_fun (eq_on (range h)) A f g \ rel_fun (BNF_Def.Grp UNIV h)\\ A f (map_fun h id g)" by(auto simp add: rel_fun_def Grp_def eq_onp_def) lemma map_fun2_id: "map_fun f g x = g \ map_fun f id x" by(simp add: map_fun_def o_assoc) lemma rel_fun_refl_eq_onp: "(\z. z \ f ` X \ A z z) \ rel_fun (eq_on X) A f f" by(auto simp add: rel_fun_def eq_onp_def) lemma map_fun_id2_in: "map_fun g h f = map_fun g id (h \ f)" by(simp add: map_fun_def) lemma Domainp_rel_fun_le: "Domainp (rel_fun A B) \ pred_fun (Domainp A) (Domainp B)" by(auto dest: rel_funD) lemma eq_onE: "\ eq_on X a b; \ b \ X; a = b \ \ thesis \ \ thesis" by auto lemma Domainp_eq_on [simp]: "Domainp (eq_on X) = (\x. x \ X)" by auto declare eq_on_def [simp del] lemma pred_prod_mono' [mono]: "pred_prod A B xy \ pred_prod A' B' xy" if "\x. A x \ A' x" "\y. B y \ B' y" using that by(cases xy) auto fun rel_witness_prod :: "('a \ 'b) \ ('c \ 'd) \ (('a \ 'c) \ ('b \ 'd))" where "rel_witness_prod ((a, b), (c, d)) = ((a, c), (b, d))" consts relcompp_witness :: "('a \ 'b \ bool) \ ('b \ 'c \ bool) \ 'a \ 'c \ 'b" specification (relcompp_witness) relcompp_witness1: "(A OO B) (fst xy) (snd xy) \ A (fst xy) (relcompp_witness A B xy)" relcompp_witness2: "(A OO B) (fst xy) (snd xy) \ B (relcompp_witness A B xy) (snd xy)" apply(fold all_conj_distrib) apply(rule choice allI)+ by(auto intro: choice allI) lemmas relcompp_witness[of _ _ "(x, y)" for x y, simplified] = relcompp_witness1 relcompp_witness2 hide_fact (open) relcompp_witness1 relcompp_witness2 lemma relcompp_witness_eq [simp]: "relcompp_witness (=) (=) (x, x) = x" using relcompp_witness(1)[of "(=)" "(=)" x x] by(simp add: eq_OO) fun rel_witness_option :: "'a option \ 'b option \ ('a \ 'b) option" where "rel_witness_option (Some x, Some y) = Some (x, y)" | "rel_witness_option (None, None) = None" | "rel_witness_option _ = None" \ \Just to make the definition complete\ lemma rel_witness_option: shows set_rel_witness_option: "\ rel_option A x y; (a, b) \ set_option (rel_witness_option (x, y)) \ \ A a b" and map1_rel_witness_option: "rel_option A x y \ map_option fst (rel_witness_option (x, y)) = x" and map2_rel_witness_option: "rel_option A x y \ map_option snd (rel_witness_option (x, y)) = y" by(cases "(x, y)" rule: rel_witness_option.cases; simp; fail)+ lemma rel_witness_option1: assumes "rel_option A x y" shows "rel_option (\a (a', b). a = a' \ A a' b) x (rel_witness_option (x, y))" using map1_rel_witness_option[OF assms, symmetric] unfolding option.rel_eq[symmetric] option.rel_map by(rule option.rel_mono_strong)(auto intro: set_rel_witness_option[OF assms]) lemma rel_witness_option2: assumes "rel_option A x y" shows "rel_option (\(a, b') b. b = b' \ A a b') (rel_witness_option (x, y)) y" using map2_rel_witness_option[OF assms] unfolding option.rel_eq[symmetric] option.rel_map by(rule option.rel_mono_strong)(auto intro: set_rel_witness_option[OF assms]) definition rel_witness_fun :: "('a \ 'b \ bool) \ ('b \ 'c \ bool) \ ('a \ 'd) \ ('c \ 'e) \ ('b \ 'd \ 'e)" where "rel_witness_fun A A' = (\(f, g) b. (f (THE a. A a b), g (THE c. A' b c)))" lemma assumes fg: "rel_fun (A OO A') B f g" and A: "left_unique A" "right_total A" and A': "right_unique A'" "left_total A'" shows rel_witness_fun1: "rel_fun A (\x (x', y). x = x' \ B x' y) f (rel_witness_fun A A' (f, g))" and rel_witness_fun2: "rel_fun A' (\(x, y') y. y = y' \ B x y') (rel_witness_fun A A' (f, g)) g" proof (goal_cases) case 1 have "A x y \ f x = f (THE a. A a y) \ B (f (THE a. A a y)) (g (The (A' y)))" for x y by(rule left_totalE[OF A'(2)]; erule meta_allE[of _ y]; erule exE; frule (1) fg[THEN rel_funD, OF relcomppI]) (auto intro!: arg_cong[where f=f] arg_cong[where f=g] rel_funI the_equality the_equality[symmetric] dest: left_uniqueD[OF A(1)] right_uniqueD[OF A'(1)] elim!: arg_cong2[where f=B, THEN iffD2, rotated -1]) with 1 show ?case by(clarsimp simp add: rel_fun_def rel_witness_fun_def) next case 2 have "A' x y \ g y = g (The (A' x)) \ B (f (THE a. A a x)) (g (The (A' x)))" for x y by(rule right_totalE[OF A(2), of x]; frule (1) fg[THEN rel_funD, OF relcomppI]) (auto intro!: arg_cong[where f=f] arg_cong[where f=g] rel_funI the_equality the_equality[symmetric] dest: left_uniqueD[OF A(1)] right_uniqueD[OF A'(1)] elim!: arg_cong2[where f=B, THEN iffD2, rotated -1]) with 2 show ?case by(clarsimp simp add: rel_fun_def rel_witness_fun_def) qed lemma rel_witness_fun_eq [simp]: "rel_witness_fun (=) (=) (f, g) = (\x. (f x, g x))" by(simp add: rel_witness_fun_def) consts rel_witness_pmf :: "('a \ 'b \ bool) \ 'a pmf \ 'b pmf \ ('a \ 'b) pmf" specification (rel_witness_pmf) set_rel_witness_pmf': "rel_pmf A (fst xy) (snd xy) \ set_pmf (rel_witness_pmf A xy) \ {(a, b). A a b}" map1_rel_witness_pmf': "rel_pmf A (fst xy) (snd xy) \ map_pmf fst (rel_witness_pmf A xy) = fst xy" map2_rel_witness_pmf': "rel_pmf A (fst xy) (snd xy) \ map_pmf snd (rel_witness_pmf A xy) = snd xy" apply(fold all_conj_distrib imp_conjR) apply(rule choice allI)+ apply(unfold pmf.in_rel) by blast lemmas set_rel_witness_pmf = set_rel_witness_pmf'[of _ "(x, y)" for x y, simplified] lemmas map1_rel_witness_pmf = map1_rel_witness_pmf'[of _ "(x, y)" for x y, simplified] lemmas map2_rel_witness_pmf = map2_rel_witness_pmf'[of _ "(x, y)" for x y, simplified] lemmas rel_witness_pmf = set_rel_witness_pmf map1_rel_witness_pmf map2_rel_witness_pmf lemma rel_witness_pmf1: assumes "rel_pmf A p q" shows "rel_pmf (\a (a', b). a = a' \ A a' b) p (rel_witness_pmf A (p, q))" using map1_rel_witness_pmf[OF assms, symmetric] unfolding pmf.rel_eq[symmetric] pmf.rel_map by(rule pmf.rel_mono_strong)(auto dest: set_rel_witness_pmf[OF assms, THEN subsetD]) lemma rel_witness_pmf2: assumes "rel_pmf A p q" shows "rel_pmf (\(a, b') b. b = b' \ A a b') (rel_witness_pmf A (p, q)) q" using map2_rel_witness_pmf[OF assms] unfolding pmf.rel_eq[symmetric] pmf.rel_map by(rule pmf.rel_mono_strong)(auto dest: set_rel_witness_pmf[OF assms, THEN subsetD]) definition rel_witness_spmf :: "('a \ 'b \ bool) \ 'a spmf \ 'b spmf \ ('a \ 'b) spmf" where "rel_witness_spmf A = map_pmf rel_witness_option \ rel_witness_pmf (rel_option A)" lemma assumes "rel_spmf A p q" shows rel_witness_spmf1: "rel_spmf (\a (a', b). a = a' \ A a' b) p (rel_witness_spmf A (p, q))" and rel_witness_spmf2: "rel_spmf (\(a, b') b. b = b' \ A a b') (rel_witness_spmf A (p, q)) q" by(auto simp add: pmf.rel_map rel_witness_spmf_def intro: pmf.rel_mono_strong[OF rel_witness_pmf1[OF assms]] rel_witness_option1 pmf.rel_mono_strong[OF rel_witness_pmf2[OF assms]] rel_witness_option2) primrec (transfer) enforce_option :: "('a \ bool) \ 'a option \ 'a option" where "enforce_option P (Some x) = (if P x then Some x else None)" | "enforce_option P None = None" lemma set_enforce_option [simp]: "set_option (enforce_option P x) = {a \ set_option x. P a}" by(cases x) auto lemma enforce_map_option: "enforce_option P (map_option f x) = map_option f (enforce_option (P \ f) x)" by(cases x) auto lemma enforce_bind_option [simp]: "enforce_option P (Option.bind x f) = Option.bind x (enforce_option P \ f)" by(cases x) auto lemma enforce_option_alt_def: "enforce_option P x = Option.bind x (\a. Option.bind (assert_option (P a)) (\_ :: unit. Some a))" by(cases x) simp_all lemma enforce_option_eq_None_iff [simp]: "enforce_option P x = None \ (\a. x = Some a \ \ P a)" by(cases x) auto lemma enforce_option_eq_Some_iff [simp]: "enforce_option P x = Some y \ x = Some y \ P y" by(cases x) auto lemma Some_eq_enforce_option_iff [simp]: "Some y = enforce_option P x \ x = Some y \ P y" by(cases x) auto lemma enforce_option_top [simp]: "enforce_option \ = id" by(rule ext; rename_tac x; case_tac x; simp) lemma enforce_option_K_True [simp]: "enforce_option (\_. True) x = x" by(cases x) simp_all lemma enforce_option_bot [simp]: "enforce_option \ = (\_. None)" by(simp add: fun_eq_iff) lemma enforce_option_K_False [simp]: "enforce_option (\_. False) x = None" by simp lemma enforce_pred_id_option: "pred_option P x \ enforce_option P x = x" by(cases x) auto lemma rel_fun_refl: "\ A \ (=); (=) \ B \ \ (=) \ rel_fun A B" by(subst fun.rel_eq[symmetric])(rule fun_mono) lemma rel_fun_mono_strong: "\ rel_fun A B f g; A' \ A; \x y. \ x \ f ` {x. Domainp A' x}; y \ g ` {x. Rangep A' x}; B x y \ \ B' x y \ \ rel_fun A' B' f g" by(auto simp add: rel_fun_def) fastforce lemma rel_fun_refl_strong: assumes "A \ (=)" "\x. x \ f ` {x. Domainp A x} \ B x x" shows "rel_fun A B f f" proof - have "rel_fun (=) (=) f f" by(simp add: rel_fun_eq) then show ?thesis using assms(1) by(rule rel_fun_mono_strong) (auto intro: assms(2)) qed lemma Grp_iff: "BNF_Def.Grp B g x y \ y = g x \ x \ B" by(simp add: Grp_def) lemma Rangep_Grp: "Rangep (BNF_Def.Grp A f) = (\x. x \ f ` A)" by(auto simp add: fun_eq_iff Grp_iff) lemma Domainp_Grp: "Domainp (BNF_Def.Grp A f) = (\x. x \ A)" by(auto simp add: Grp_iff fun_eq_iff) lemma rel_fun_Grp: "rel_fun (BNF_Def.Grp UNIV h)\\ (BNF_Def.Grp A g) = BNF_Def.Grp {f. f ` range h \ A} (map_fun h g)" by(auto simp add: rel_fun_def fun_eq_iff Grp_iff) lemma wf_strict_prefix: "wfP strict_prefix" proof - from wf have "wf (inv_image {(x, y). x < y} length)" by(rule wf_inv_image) moreover have "{(x, y). strict_prefix x y} \ inv_image {(x, y). x < y} length" by(auto intro: prefix_length_less) ultimately show ?thesis unfolding wfP_def by(rule wf_subset) qed lemma strict_prefix_setD: "strict_prefix xs ys \ set xs \ set ys" by(auto simp add: strict_prefix_def prefix_def) (* SPMF *) lemma weight_assert_spmf [simp]: "weight_spmf (assert_spmf b) = indicator {True} b" by(simp split: split_indicator) definition enforce_spmf :: "('a \ bool) \ 'a spmf \ 'a spmf" where "enforce_spmf P = map_pmf (enforce_option P)" lemma enforce_spmf_parametric [transfer_rule]: includes lifting_syntax shows "((A ===> (=)) ===> rel_spmf A ===> rel_spmf A) enforce_spmf enforce_spmf" unfolding enforce_spmf_def by transfer_prover lemma enforce_return_spmf [simp]: "enforce_spmf P (return_spmf x) = (if P x then return_spmf x else return_pmf None)" by(simp add: enforce_spmf_def) lemma enforce_return_pmf_None [simp]: "enforce_spmf P (return_pmf None) = return_pmf None" by(simp add: enforce_spmf_def) lemma enforce_map_spmf: "enforce_spmf P (map_spmf f p) = map_spmf f (enforce_spmf (P \ f) p)" by(simp add: enforce_spmf_def pmf.map_comp o_def enforce_map_option) lemma enforce_bind_spmf [simp]: "enforce_spmf P (bind_spmf p f) = bind_spmf p (enforce_spmf P \ f)" by(auto simp add: enforce_spmf_def bind_spmf_def map_bind_pmf intro!: bind_pmf_cong split: option.split) lemma set_enforce_spmf [simp]: "set_spmf (enforce_spmf P p) = {a \ set_spmf p. P a}" by(auto simp add: enforce_spmf_def in_set_spmf) lemma enforce_spmf_alt_def: "enforce_spmf P p = bind_spmf p (\a. bind_spmf (assert_spmf (P a)) (\_ :: unit. return_spmf a))" by(auto simp add: enforce_spmf_def assert_spmf_def map_pmf_def bind_spmf_def bind_return_pmf intro!: bind_pmf_cong split: option.split) lemma bind_enforce_spmf [simp]: "bind_spmf (enforce_spmf P p) f = bind_spmf p (\x. if P x then f x else return_pmf None)" by(auto simp add: enforce_spmf_alt_def assert_spmf_def intro!: bind_spmf_cong) lemma weight_enforce_spmf: "weight_spmf (enforce_spmf P p) = weight_spmf p - measure (measure_spmf p) {x. \ P x}" (is "?lhs = ?rhs") proof - have "?lhs = LINT x|measure_spmf p. indicator {x. P x} x" by(auto simp add: enforce_spmf_alt_def weight_bind_spmf o_def simp del: Bochner_Integration.integral_indicator intro!: Bochner_Integration.integral_cong split: split_indicator) also have "\ = ?rhs" by(subst measure_spmf.finite_measure_Diff[symmetric])(auto simp add: space_measure_spmf intro!: arg_cong2[where f=measure]) finally show ?thesis . qed lemma lossless_enforce_spmf [simp]: "lossless_spmf (enforce_spmf P p) \ lossless_spmf p \ set_spmf p \ {x. P x}" by(auto simp add: enforce_spmf_alt_def) lemma enforce_spmf_top [simp]: "enforce_spmf \ = id" by(simp add: enforce_spmf_def) lemma enforce_spmf_K_True [simp]: "enforce_spmf (\_. True) p = p" using enforce_spmf_top[THEN fun_cong, of p] by(simp add: top_fun_def) lemma enforce_spmf_bot [simp]: "enforce_spmf \ = (\_. return_pmf None)" by(simp add: enforce_spmf_def fun_eq_iff) lemma enforce_spmf_K_False [simp]: "enforce_spmf (\_. False) p = return_pmf None" using enforce_spmf_bot[THEN fun_cong, of p] by(simp add: bot_fun_def) lemma enforce_pred_id_spmf: "enforce_spmf P p = p" if "pred_spmf P p" proof - have "enforce_spmf P p = map_pmf id p" using that by(auto simp add: enforce_spmf_def enforce_pred_id_option simp del: map_pmf_id intro!: pmf.map_cong_pred[OF refl] elim!: pmf_pred_mono_strong) then show ?thesis by simp qed lemma map_the_spmf_of_pmf [simp]: "map_pmf the (spmf_of_pmf p) = p" by(simp add: spmf_of_pmf_def pmf.map_comp o_def) lemma bind_bind_conv_pair_spmf: "bind_spmf p (\x. bind_spmf q (f x)) = bind_spmf (pair_spmf p q) (\(x, y). f x y)" by(simp add: pair_spmf_alt_def) lemma cond_pmf_of_set: assumes fin: "finite A" and nonempty: "A \ B \ {}" shows "cond_pmf (pmf_of_set A) B = pmf_of_set (A \ B)" (is "?lhs = ?rhs") proof(rule pmf_eqI) from nonempty have A: "A \ {}" by auto show "pmf ?lhs x = pmf ?rhs x" for x by(subst pmf_cond; clarsimp simp add: fin A nonempty measure_pmf_of_set split: split_indicator) qed lemma cond_spmf_spmf_of_set: "cond_spmf (spmf_of_set A) B = spmf_of_set (A \ B)" if "finite A" by(rule spmf_eqI)(auto simp add: spmf_of_set measure_spmf_of_set that split: split_indicator) lemma pair_pmf_of_set: assumes A: "finite A" "A \ {}" and B: "finite B" "B \ {}" shows "pair_pmf (pmf_of_set A) (pmf_of_set B) = pmf_of_set (A \ B)" by(rule pmf_eqI)(clarsimp simp add: pmf_pair assms split: split_indicator) lemma pair_spmf_of_set: "pair_spmf (spmf_of_set A) (spmf_of_set B) = spmf_of_set (A \ B)" by(rule spmf_eqI)(clarsimp simp add: spmf_of_set card_cartesian_product split: split_indicator) (*lemma cond_bind_pmf: assumes *: "\x. x \ set_pmf p \ set_pmf (f x) \ A \ {}" shows "cond_pmf (bind_pmf p f) A = bind_pmf p (\x. cond_pmf (f x) A)" apply(rule pmf_eqI) apply(subst pmf_cond) subgoal using * set_pmf_not_empty[of p] by auto apply clarsimp oops*) lemma emeasure_cond_pmf: fixes p A defines "q \ cond_pmf p A" assumes "set_pmf p \ A \ {}" shows "emeasure (measure_pmf q) B = emeasure (measure_pmf p) (A \ B) / emeasure (measure_pmf p) A" proof - note [transfer_rule] = cond_pmf.transfer[OF assms(2), folded q_def] interpret pmf_as_measure . show ?thesis by transfer simp qed lemma measure_cond_pmf: "measure (measure_pmf (cond_pmf p A)) B = measure (measure_pmf p) (A \ B) / measure (measure_pmf p) A" if "set_pmf p \ A \ {}" using emeasure_cond_pmf[OF that, of B] that by(auto simp add: measure_pmf.emeasure_eq_measure measure_pmf_posI divide_ennreal) lemma emeasure_measure_pmf_zero_iff: "emeasure (measure_pmf p) s = 0 \ set_pmf p \ s = {}" (is "?lhs = ?rhs") proof - have "?lhs \ (AE x in measure_pmf p. x \ s)" by(subst AE_iff_measurable)(auto) also have "\ = ?rhs" by(auto simp add: AE_measure_pmf_iff) finally show ?thesis . qed lemma emeasure_cond_spmf: "emeasure (measure_spmf (cond_spmf p A)) B = emeasure (measure_spmf p) (A \ B) / emeasure (measure_spmf p) A" apply(clarsimp simp add: cond_spmf_def emeasure_measure_spmf_conv_measure_pmf emeasure_measure_pmf_zero_iff set_pmf_Int_Some split!: if_split) apply blast apply(subst (asm) emeasure_cond_pmf) by(auto simp add: set_pmf_Int_Some image_Int) lemma measure_cond_spmf: "measure (measure_spmf (cond_spmf p A)) B = measure (measure_spmf p) (A \ B) / measure (measure_spmf p) A" apply(clarsimp simp add: cond_spmf_def measure_measure_spmf_conv_measure_pmf measure_pmf_zero_iff set_pmf_Int_Some split!: if_split) apply(subst (asm) measure_cond_pmf) by(auto simp add: image_Int set_pmf_Int_Some) lemma lossless_cond_spmf [simp]: "lossless_spmf (cond_spmf p A) \ set_spmf p \ A \ {}" by(clarsimp simp add: cond_spmf_def lossless_iff_set_pmf_None set_pmf_Int_Some) lemma measure_spmf_eq_density: "measure_spmf p = density (count_space UNIV) (spmf p)" by(rule measure_eqI)(simp_all add: emeasure_density nn_integral_spmf[symmetric] nn_integral_count_space_indicator) lemma integral_measure_spmf: fixes f :: "'a \ 'b::{banach, second_countable_topology}" assumes A: "finite A" shows "(\a. a \ set_spmf M \ f a \ 0 \ a \ A) \ (LINT x|measure_spmf M. f x) = (\a\A. spmf M a *\<^sub>R f a)" unfolding measure_spmf_eq_density apply (simp add: integral_density) apply (subst lebesgue_integral_count_space_finite_support) by (auto intro!: finite_subset[OF _ \finite A\] sum.mono_neutral_left simp: spmf_eq_0_set_spmf) lemma image_set_spmf_eq: "f ` set_spmf p = g ` set_spmf q" if "ASSUMPTION (map_spmf f p = map_spmf g q)" using that[unfolded ASSUMPTION_def, THEN arg_cong[where f=set_spmf]] by simp lemma map_spmf_const: "map_spmf (\_. x) p = scale_spmf (weight_spmf p) (return_spmf x)" by(simp add: map_spmf_conv_bind_spmf bind_spmf_const) lemma cond_return_pmf [simp]: "cond_pmf (return_pmf x) A = return_pmf x" if "x \ A" using that by(intro pmf_eqI)(auto simp add: pmf_cond split: split_indicator) lemma cond_return_spmf [simp]: "cond_spmf (return_spmf x) A = (if x \ A then return_spmf x else return_pmf None)" by(simp add: cond_spmf_def) lemma measure_range_Some_eq_weight: "measure (measure_pmf p) (range Some) = weight_spmf p" by (simp add: measure_measure_spmf_conv_measure_pmf space_measure_spmf) lemma restrict_spmf_eq_return_pmf_None [simp]: "restrict_spmf p A = return_pmf None \ set_spmf p \ A = {}" by(auto 4 3 simp add: restrict_spmf_def map_pmf_eq_return_pmf_iff bind_UNION in_set_spmf bind_eq_None_conv option.the_def dest: bspec split: if_split_asm option.split_asm) lemma integrable_scale_measure [simp]: "\ integrable M f; r < \ \ \ integrable (scale_measure r M) f" for f :: "'a \ 'b::{banach, second_countable_topology}" by(auto simp add: integrable_iff_bounded nn_integral_scale_measure ennreal_mult_less_top) lemma integral_scale_measure: assumes "integrable M f" "r < \" shows "integral\<^sup>L (scale_measure r M) f = enn2real r * integral\<^sup>L M f" using assms apply(subst (1 2) real_lebesgue_integral_def) apply(simp_all add: nn_integral_scale_measure ennreal_enn2real_if) by(auto simp add: ennreal_mult_less_top ennreal_less_top_iff ennreal_mult_eq_top_iff enn2real_mult right_diff_distrib elim!: integrableE) definition mk_lossless :: "'a spmf \ 'a spmf" where "mk_lossless p = scale_spmf (inverse (weight_spmf p)) p" lemma mk_lossless_idem [simp]: "mk_lossless (mk_lossless p) = mk_lossless p" by(simp add: mk_lossless_def weight_scale_spmf min_def max_def inverse_eq_divide) lemma mk_lossless_return [simp]: "mk_lossless (return_pmf x) = return_pmf x" by(cases x)(simp_all add: mk_lossless_def) lemma mk_lossless_map [simp]: "mk_lossless (map_spmf f p) = map_spmf f (mk_lossless p)" by(simp add: mk_lossless_def map_scale_spmf) lemma spmf_mk_lossless [simp]: "spmf (mk_lossless p) x = spmf p x / weight_spmf p" by(simp add: mk_lossless_def spmf_scale_spmf inverse_eq_divide max_def) lemma set_spmf_mk_lossless [simp]: "set_spmf (mk_lossless p) = set_spmf p" by(simp add: mk_lossless_def set_scale_spmf measure_spmf_zero_iff zero_less_measure_iff) lemma mk_lossless_lossless [simp]: "lossless_spmf p \ mk_lossless p = p" by(simp add: mk_lossless_def lossless_weight_spmfD) lemma mk_lossless_eq_return_pmf_None [simp]: "mk_lossless p = return_pmf None \ p = return_pmf None" proof - have aux: "weight_spmf p = 0 \ spmf p i = 0" for i by(rule antisym, rule order_trans[OF spmf_le_weight]) (auto intro!: order_trans[OF spmf_le_weight]) have[simp]: " spmf (scale_spmf (inverse (weight_spmf p)) p) = spmf (return_pmf None) \ spmf p i = 0" for i by(drule fun_cong[where x=i]) (auto simp add: aux spmf_scale_spmf max_def) show ?thesis by(auto simp add: mk_lossless_def intro: spmf_eqI) qed lemma return_pmf_None_eq_mk_lossless [simp]: "return_pmf None = mk_lossless p \ p = return_pmf None" by(metis mk_lossless_eq_return_pmf_None) lemma mk_lossless_spmf_of_set [simp]: "mk_lossless (spmf_of_set A) = spmf_of_set A" by(simp add: spmf_of_set_def del: spmf_of_pmf_pmf_of_set) lemma weight_mk_lossless: "weight_spmf (mk_lossless p) = (if p = return_pmf None then 0 else 1)" by(simp add: mk_lossless_def weight_scale_spmf min_def max_def inverse_eq_divide weight_spmf_eq_0) lemma mk_lossless_parametric [transfer_rule]: includes lifting_syntax shows "(rel_spmf A ===> rel_spmf A) mk_lossless mk_lossless" by(simp add: mk_lossless_def rel_fun_def rel_spmf_weightD rel_spmf_scaleI) lemma rel_spmf_mk_losslessI: "rel_spmf A p q \ rel_spmf A (mk_lossless p) (mk_lossless q)" by(rule mk_lossless_parametric[THEN rel_funD]) lemma rel_spmf_restrict_spmfI: "rel_spmf (\x y. (x \ A \ y \ B \ R x y) \ x \ A \ y \ B) p q \ rel_spmf R (restrict_spmf p A) (restrict_spmf q B)" by(auto simp add: restrict_spmf_def pmf.rel_map elim!: option.rel_cases pmf.rel_mono_strong) lemma cond_spmf_alt: "cond_spmf p A = mk_lossless (restrict_spmf p A)" proof(cases "set_spmf p \ A = {}") case True then show ?thesis by(simp add: cond_spmf_def measure_spmf_zero_iff) next case False show ?thesis by(rule spmf_eqI)(simp add: False cond_spmf_def pmf_cond set_pmf_Int_Some image_iff measure_measure_spmf_conv_measure_pmf[symmetric] spmf_scale_spmf max_def inverse_eq_divide) qed lemma cond_spmf_bind: "cond_spmf (bind_spmf p f) A = mk_lossless (p \ (\x. f x \ A))" by(simp add: cond_spmf_alt restrict_bind_spmf scale_bind_spmf) lemma cond_spmf_UNIV [simp]: "cond_spmf p UNIV = mk_lossless p" by(clarsimp simp add: cond_spmf_alt) lemma cond_pmf_singleton: "cond_pmf p A = return_pmf x" if "set_pmf p \ A = {x}" proof - have[simp]: "set_pmf p \ A = {x} \ x \ A \ measure_pmf.prob p A = pmf p x" by(auto simp add: measure_pmf_single[symmetric] AE_measure_pmf_iff intro!: measure_pmf.finite_measure_eq_AE) have "pmf (cond_pmf p A) i = pmf (return_pmf x) i" for i using that by(auto simp add: pmf_cond measure_pmf_zero_iff pmf_eq_0_set_pmf split: split_indicator) then show ?thesis by(rule pmf_eqI) qed definition cond_spmf_fst :: "('a \ 'b) spmf \ 'a \ 'b spmf" where "cond_spmf_fst p a = map_spmf snd (cond_spmf p ({a} \ UNIV))" lemma cond_spmf_fst_return_spmf [simp]: "cond_spmf_fst (return_spmf (x, y)) x = return_spmf y" by(simp add: cond_spmf_fst_def) lemma cond_spmf_fst_map_Pair [simp]: "cond_spmf_fst (map_spmf (Pair x) p) x = mk_lossless p" by(clarsimp simp add: cond_spmf_fst_def spmf.map_comp o_def) lemma cond_spmf_fst_map_Pair' [simp]: "cond_spmf_fst (map_spmf (\y. (x, f y)) p) x = map_spmf f (mk_lossless p)" by(subst spmf.map_comp[where f="Pair x", symmetric, unfolded o_def]) simp lemma cond_spmf_fst_eq_return_None [simp]: "cond_spmf_fst p x = return_pmf None \ x \ fst ` set_spmf p" by(auto 4 4 simp add: cond_spmf_fst_def map_pmf_eq_return_pmf_iff in_set_spmf[symmetric] dest: bspec[where x="Some _"] intro: ccontr rev_image_eqI) lemma cond_spmf_fst_map_Pair1: "cond_spmf_fst (map_spmf (\x. (f x, g x)) p) (f x) = return_spmf (g (inv_into (set_spmf p) f (f x)))" if "x \ set_spmf p" "inj_on f (set_spmf p)" proof - let ?foo="\y. map_option (\x. (f x, g x)) -` Some ` ({f y} \ UNIV)" have[simp]: "y \ set_spmf p \ f x = f y \ set_pmf p \ (?foo y) \ {}" for y by(auto simp add: vimage_def image_def in_set_spmf) have[simp]: "y \ set_spmf p \ f x = f y \ map_spmf snd (map_spmf (\x. (f x, g x)) (cond_pmf p (?foo y))) = return_spmf (g x)" for y using that by(subst cond_pmf_singleton[where x="Some x"]) (auto simp add: in_set_spmf elim: inj_onD) show ?thesis using that by(auto simp add: cond_spmf_fst_def cond_spmf_def) (erule notE, subst cond_map_pmf, simp_all) qed lemma lossless_cond_spmf_fst [simp]: "lossless_spmf (cond_spmf_fst p x) \ x \ fst ` set_spmf p" by(auto simp add: cond_spmf_fst_def intro: rev_image_eqI) lemma cond_spmf_fst_inverse: "bind_spmf (map_spmf fst p) (\x. map_spmf (Pair x) (cond_spmf_fst p x)) = p" (is "?lhs = ?rhs") proof(rule spmf_eqI) fix i :: "'a \ 'b" have *: "({x} \ UNIV \ (Pair x \ snd) -` {i}) = (if x = fst i then {i} else {})" for x by(cases i)auto have "spmf ?lhs i = LINT x|measure_spmf (map_spmf fst p). spmf (map_spmf (Pair x \ snd) (cond_spmf p ({x} \ UNIV))) i" by(auto simp add: spmf_bind spmf.map_comp[symmetric] cond_spmf_fst_def intro!: integral_cong_AE) also have "\ = LINT x|measure_spmf (map_spmf fst p). measure (measure_spmf (cond_spmf p ({x} \ UNIV))) ((Pair x \ snd) -` {i})" by(rule integral_cong_AE)(auto simp add: spmf_map) also have "\ = LINT x|measure_spmf (map_spmf fst p). measure (measure_spmf p) ({x} \ UNIV \ (Pair x \ snd) -` {i}) / measure (measure_spmf p) ({x} \ UNIV)" by(rule integral_cong_AE; clarsimp simp add: measure_cond_spmf) also have "\ = spmf (map_spmf fst p) (fst i) * spmf p i / measure (measure_spmf p) ({fst i} \ UNIV)" by(simp add: * if_distrib[where f="measure (measure_spmf _)"] cong: if_cong) (subst integral_measure_spmf[where A="{fst i}"]; auto split: if_split_asm simp add: spmf_conv_measure_spmf) also have "\ = spmf p i" by(clarsimp simp add: spmf_map vimage_fst)(metis (no_types, lifting) Int_insert_left_if1 in_set_spmf_iff_spmf insertI1 insert_UNIV insert_absorb insert_not_empty measure_spmf_zero_iff mem_Sigma_iff prod.collapse) finally show "spmf ?lhs i = spmf ?rhs i" . qed (* Generat *) fun rel_witness_generat :: "('a, 'c, 'e) generat \ ('b, 'd, 'f) generat \ ('a \ 'b, 'c \ 'd, 'e \ 'f) generat" where "rel_witness_generat (Pure x, Pure y) = Pure (x, y)" | "rel_witness_generat (IO out c, IO out' c') = IO (out, out') (c, c')" lemma rel_witness_generat: assumes "rel_generat A C R x y" shows pures_rel_witness_generat: "generat_pures (rel_witness_generat (x, y)) \ {(a, b). A a b}" and outs_rel_witness_generat: "generat_outs (rel_witness_generat (x, y)) \ {(c, d). C c d}" and conts_rel_witness_generat: "generat_conts (rel_witness_generat (x, y)) \ {(e, f). R e f}" and map1_rel_witness_generat: "map_generat fst fst fst (rel_witness_generat (x, y)) = x" and map2_rel_witness_generat: "map_generat snd snd snd (rel_witness_generat (x, y)) = y" using assms by(cases; simp; fail)+ lemmas set_rel_witness_generat = pures_rel_witness_generat outs_rel_witness_generat conts_rel_witness_generat lemma rel_witness_generat1: assumes "rel_generat A C R x y" shows "rel_generat (\a (a', b). a = a' \ A a' b) (\c (c', d). c = c' \ C c' d) (\r (r', s). r = r' \ R r' s) x (rel_witness_generat (x, y))" using map1_rel_witness_generat[OF assms, symmetric] unfolding generat.rel_eq[symmetric] generat.rel_map by(rule generat.rel_mono_strong)(auto dest: set_rel_witness_generat[OF assms, THEN subsetD]) lemma rel_witness_generat2: assumes "rel_generat A C R x y" shows "rel_generat (\(a, b') b. b = b' \ A a b') (\(c, d') d. d = d' \ C c d') (\(r, s') s. s = s' \ R r s') (rel_witness_generat (x, y)) y" using map2_rel_witness_generat[OF assms] unfolding generat.rel_eq[symmetric] generat.rel_map by(rule generat.rel_mono_strong)(auto dest: set_rel_witness_generat[OF assms, THEN subsetD]) (* Generative_Probabilistic_Value *) lemma rel_gpv''_map_gpv1: "rel_gpv'' A C R (map_gpv f g gpv) gpv' = rel_gpv'' (\a. A (f a)) (\c. C (g c)) R gpv gpv'" (is "?lhs = ?rhs") proof show ?rhs if ?lhs using that apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(simp add: gpv.map_sel spmf_rel_map) apply(erule rel_spmf_mono) by(auto simp add: generat.rel_map rel_fun_comp elim!: generat.rel_mono_strong rel_fun_mono) show ?lhs if ?rhs using that apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(simp add: gpv.map_sel spmf_rel_map) apply(erule rel_spmf_mono) by(auto simp add: generat.rel_map rel_fun_comp elim!: generat.rel_mono_strong rel_fun_mono) qed lemma rel_gpv''_map_gpv2: "rel_gpv'' A C R gpv (map_gpv f g gpv') = rel_gpv'' (\a b. A a (f b)) (\c d. C c (g d)) R gpv gpv'" using rel_gpv''_map_gpv1[of "conversep A" "conversep C" "conversep R" f g gpv' gpv] apply(rewrite in "\ = _" conversep_iff[symmetric]) apply(rewrite in "_ = \" conversep_iff[symmetric]) apply(simp only: rel_gpv''_conversep) apply(simp only: rel_gpv''_conversep[symmetric]) apply(simp only: conversep_iff[abs_def]) done lemmas rel_gpv''_map_gpv = rel_gpv''_map_gpv1[abs_def] rel_gpv''_map_gpv2 lemma rel_gpv''_map_gpv' [simp]: shows "\f g h gpv. NO_MATCH id f \ NO_MATCH id g \ rel_gpv'' A C R (map_gpv' f g h gpv) = rel_gpv'' (\a. A (f a)) (\c. C (g c)) R (map_gpv' id id h gpv)" and "\f g h gpv gpv'. NO_MATCH id f \ NO_MATCH id g \ rel_gpv'' A C R gpv (map_gpv' f g h gpv') = rel_gpv'' (\a b. A a (f b)) (\c d. C c (g d)) R gpv (map_gpv' id id h gpv')" proof (goal_cases) case (1 f g h gpv) then show ?case using map_gpv'_comp[of f g id id id h gpv, symmetric] by(simp add: rel_gpv''_map_gpv[unfolded map_gpv_conv_map_gpv']) next case (2 f g h gpv gpv') then show ?case using map_gpv'_comp[of f g id id id h gpv', symmetric] by(simp add: rel_gpv''_map_gpv[unfolded map_gpv_conv_map_gpv']) qed lemmas rel_gpv_map_gpv' = rel_gpv''_map_gpv'[where R="(=)", folded rel_gpv_conv_rel_gpv''] definition rel_witness_gpv :: "('a \ 'd \ bool) \ ('b \ 'e \ bool) \ ('c \ 'g \ bool) \ ('g \ 'f \ bool) \ ('a, 'b, 'c) gpv \ ('d, 'e, 'f) gpv \ ('a \ 'd, 'b \ 'e, 'g) gpv" where "rel_witness_gpv A C R R' = corec_gpv ( map_spmf (map_generat id id (\(rpv, rpv'). (Inr \ rel_witness_fun R R' (rpv, rpv'))) \ rel_witness_generat) \ rel_witness_spmf (rel_generat A C (rel_fun (R OO R') (rel_gpv'' A C (R OO R')))) \ map_prod the_gpv the_gpv)" lemma rel_witness_gpv_sel [simp]: "the_gpv (rel_witness_gpv A C R R' (gpv, gpv')) = map_spmf (map_generat id id (\(rpv, rpv'). (rel_witness_gpv A C R R' \ rel_witness_fun R R' (rpv, rpv'))) \ rel_witness_generat) (rel_witness_spmf (rel_generat A C (rel_fun (R OO R') (rel_gpv'' A C (R OO R')))) (the_gpv gpv, the_gpv gpv'))" unfolding rel_witness_gpv_def by(auto simp add: spmf.map_comp generat.map_comp o_def intro!: map_spmf_cong generat.map_cong) lemma assumes "rel_gpv'' A C (R OO R') gpv gpv'" and R: "left_unique R" "right_total R" and R': "right_unique R'" "left_total R'" shows rel_witness_gpv1: "rel_gpv'' (\a (a', b). a = a' \ A a' b) (\c (c', d). c = c' \ C c' d) R gpv (rel_witness_gpv A C R R' (gpv, gpv'))" (is "?thesis1") and rel_witness_gpv2: "rel_gpv'' (\(a, b') b. b = b' \ A a b') (\(c, d') d. d = d' \ C c d') R' (rel_witness_gpv A C R R' (gpv, gpv')) gpv'" (is "?thesis2") proof - show ?thesis1 using assms(1) proof(coinduction arbitrary: gpv gpv') case rel_gpv'' from this[THEN rel_gpv''D] show ?case by(auto simp add: spmf_rel_map generat.rel_map rel_fun_comp elim!: rel_fun_mono[OF rel_witness_fun1[OF _ R R']] rel_spmf_mono[OF rel_witness_spmf1] generat.rel_mono[THEN predicate2D, rotated -1, OF rel_witness_generat1]) qed show ?thesis2 using assms(1) proof(coinduction arbitrary: gpv gpv') case rel_gpv'' from this[THEN rel_gpv''D] show ?case by(simp add: spmf_rel_map) (erule rel_spmf_mono[OF rel_witness_spmf2] , auto simp add: generat.rel_map rel_fun_comp elim!: rel_fun_mono[OF rel_witness_fun2[OF _ R R']] generat.rel_mono[THEN predicate2D, rotated -1, OF rel_witness_generat2]) qed qed lemma rel_gpv''_neg_distr: assumes R: "left_unique R" "right_total R" and R': "right_unique R'" "left_total R'" shows "rel_gpv'' (A OO A') (C OO C') (R OO R') \ rel_gpv'' A C R OO rel_gpv'' A' C' R'" proof(rule predicate2I relcomppI)+ fix gpv gpv'' assume *: "rel_gpv'' (A OO A') (C OO C') (R OO R') gpv gpv''" let ?gpv' = "map_gpv (relcompp_witness A A') (relcompp_witness C C') (rel_witness_gpv (A OO A') (C OO C') R R' (gpv, gpv''))" show "rel_gpv'' A C R gpv ?gpv'" using rel_witness_gpv1[OF * R R'] unfolding rel_gpv''_map_gpv by(rule rel_gpv''_mono[THEN predicate2D, rotated -1]; clarify del: relcomppE elim!: relcompp_witness) show "rel_gpv'' A' C' R' ?gpv' gpv''" using rel_witness_gpv2[OF * R R'] unfolding rel_gpv''_map_gpv by(rule rel_gpv''_mono[THEN predicate2D, rotated -1]; clarify del: relcomppE elim!: relcompp_witness) qed lemma rel_gpv''_mono' [mono]: assumes "\x y. A x y \ A' x y" and "\x y. C x y \ C' x y" and "\x y. R' x y \ R x y" shows "rel_gpv'' A C R gpv gpv' \ rel_gpv'' A' C' R' gpv gpv'" using rel_gpv''_mono[of A A' C C' R' R] assms by(blast) context includes \.lifting begin lift_definition \_uniform :: "'out set \ 'in set \ ('out, 'in) \" is "\A B x. if x \ A then B else {}" . lemma outs_\_uniform [simp]: "outs_\ (\_uniform A B) = (if B = {} then {} else A)" by transfer simp lemma responses_\_uniform [simp]: "responses_\ (\_uniform A B) x = (if x \ A then B else {})" by transfer simp lemma \_uniform_UNIV [simp]: "\_uniform UNIV UNIV = \_full" (* TODO: make \_full an abbreviation *) by transfer simp lifting_update \.lifting lifting_forget \.lifting end lemma \_eqI: "\ outs_\ \ = outs_\ \'; \x. x \ outs_\ \' \ responses_\ \ x = responses_\ \' x \ \ \ = \'" including \.lifting by transfer auto instantiation \ :: (type, type) order begin definition less_eq_\ :: "('a, 'b) \ \ ('a, 'b) \ \ bool" where le_\_def: "less_eq_\ \ \' \ outs_\ \ \ outs_\ \' \ (\x\outs_\ \. responses_\ \' x \ responses_\ \ x)" definition less_\ :: "('a, 'b) \ \ ('a, 'b) \ \ bool" where "less_\ = mk_less (\)" instance proof show "\ < \' \ \ \ \' \ \ \' \ \" for \ \' :: "('a, 'b) \" by(simp add: less_\_def mk_less_def) show "\ \ \" for \ :: "('a, 'b) \" by(simp add: le_\_def) show "\ \ \''" if "\ \ \'" "\' \ \''" for \ \' \'' :: "('a, 'b) \" using that by(fastforce simp add: le_\_def) show "\ = \'" if "\ \ \'" "\' \ \" for \ \' :: "('a, 'b) \" using that by(auto simp add: le_\_def intro!: \_eqI) qed end instantiation \ :: (type, type) order_bot begin definition bot_\ :: "('a, 'b) \" where "bot_\ = \_uniform {} UNIV" instance by standard(auto simp add: bot_\_def le_\_def) end lemma outs_\_bot [simp]: "outs_\ bot = {}" by(simp add: bot_\_def) lemma respones_\_bot [simp]: "responses_\ bot x = {}" by(simp add: bot_\_def) lemma outs_\_mono: "\ \ \' \ outs_\ \ \ outs_\ \'" by(simp add: le_\_def) lemma responses_\_mono: "\ \ \ \'; x \ outs_\ \ \ \ responses_\ \' x \ responses_\ \ x" by(simp add: le_\_def) lemma \_uniform_empty [simp]: "\_uniform {} A = bot" unfolding bot_\_def including \.lifting by transfer simp lemma WT_gpv_\_mono: "\ \ \g gpv \; \ \ \' \ \ \' \g gpv \" by(erule WT_gpv_mono; rule outs_\_mono responses_\_mono) lemma results_gpv_mono: assumes le: "\' \ \" and WT: "\' \g gpv \" shows "results_gpv \ gpv \ results_gpv \' gpv" proof(rule subsetI, goal_cases) case (1 x) show ?case using 1 WT by(induction)(auto 4 3 intro: results_gpv.intros responses_\_mono[OF le, THEN subsetD] intro: WT_gpvD) qed lemma \_uniform_mono: "\_uniform A B \ \_uniform C D" if "A \ C" "D \ B" "D = {} \ B = {}" unfolding le_\_def using that by auto context begin qualified inductive outsp_gpv :: "('out, 'in) \ \ 'out \ ('a, 'out, 'in) gpv \ bool" for \ x where IO: "IO x c \ set_spmf (the_gpv gpv) \ outsp_gpv \ x gpv" | Cont: "\ IO out rpv \ set_spmf (the_gpv gpv); input \ responses_\ \ out; outsp_gpv \ x (rpv input) \ \ outsp_gpv \ x gpv" definition outs_gpv :: "('out, 'in) \ \ ('a, 'out, 'in) gpv \ 'out set" where "outs_gpv \ gpv \ {x. outsp_gpv \ x gpv}" lemma outsp_gpv_outs_gpv_eq [pred_set_conv]: "outsp_gpv \ x = (\gpv. x \ outs_gpv \ gpv)" by(simp add: outs_gpv_def) context begin local_setup \Local_Theory.map_background_naming (Name_Space.mandatory_path "outs_gpv")\ lemmas intros [intro?] = outsp_gpv.intros[to_set] and IO = IO[to_set] and Cont = Cont[to_set] and induct [consumes 1, case_names IO Cont, induct set: outs_gpv] = outsp_gpv.induct[to_set] and cases [consumes 1, case_names IO Cont, cases set: outs_gpv] = outsp_gpv.cases[to_set] and simps = outsp_gpv.simps[to_set] end inductive_simps outs_gpv_GPV [to_set, simp]: "outsp_gpv \ x (GPV gpv)" end lemma outs_gpv_Done [iff]: "outs_gpv \ (Done x) = {}" by(auto simp add: Done.ctr) lemma outs_gpv_Fail [iff]: "outs_gpv \ Fail = {}" by(auto simp add: Fail_def) lemma outs_gpv_Pause [simp]: "outs_gpv \ (Pause out c) = insert out (\input\responses_\ \ out. outs_gpv \ (c input))" by(auto simp add: Pause.ctr) lemma outs_gpv_lift_spmf [iff]: "outs_gpv \ (lift_spmf p) = {}" by(auto simp add: lift_spmf.ctr) lemma outs_gpv_assert_gpv [simp]: "outs_gpv \ (assert_gpv b) = {}" by(cases b)auto lemma outs_gpv_bind_gpv [simp]: "outs_gpv \ (gpv \ f) = outs_gpv \ gpv \ (\x\results_gpv \ gpv. outs_gpv \ (f x))" (is "?lhs = ?rhs") proof(intro Set.set_eqI iffI) fix x assume "x \ ?lhs" then show "x \ ?rhs" proof(induction gpv'\"gpv \ f" arbitrary: gpv) case IO thus ?case proof(clarsimp split: if_split_asm elim!: is_PureE not_is_PureE, goal_cases) case (1 generat) then show ?case by(cases generat)(auto intro: results_gpv.Pure outs_gpv.intros) qed next case (Cont out rpv input) thus ?case proof(clarsimp split: if_split_asm, goal_cases) case (1 generat) then show ?case by(cases generat)(auto 4 3 split: if_split_asm intro: results_gpv.intros outs_gpv.intros) qed qed next fix x assume "x \ ?rhs" then consider (out) "x \ outs_gpv \ gpv" | (result) y where "y \ results_gpv \ gpv" "x \ outs_gpv \ (f y)" by auto then show "x \ ?lhs" proof cases case out then show ?thesis by(induction) (auto 4 4 intro: outs_gpv.IO outs_gpv.Cont rev_bexI) next case result then show ?thesis by induction ((erule outs_gpv.cases | rule outs_gpv.Cont), auto 4 4 intro: outs_gpv.intros rev_bexI elim: outs_gpv.cases)+ qed qed lemma outs_gpv_\_full: "outs_gpv \_full = outs'_gpv" proof(intro ext Set.set_eqI iffI) show "x \ outs'_gpv gpv" if "x \ outs_gpv \_full gpv" for x gpv using that by induction(auto intro: outs'_gpvI) show "x \ outs_gpv \_full gpv" if "x \ outs'_gpv gpv" for x gpv using that by induction(auto intro: outs_gpv.intros elim!: generat.set_cases) qed lemma outs'_bind_gpv [simp]: "outs'_gpv (bind_gpv gpv f) = outs'_gpv gpv \ (\x\results'_gpv gpv. outs'_gpv (f x))" unfolding outs_gpv_\_full[symmetric] results_gpv_\_full[symmetric] by simp lemma outs_gpv_map_gpv_id [simp]: "outs_gpv \ (map_gpv f id gpv) = outs_gpv \ gpv" by(auto simp add: map_gpv_conv_bind id_def) lemma outs_gpv_map_gpv_id' [simp]: "outs_gpv \ (map_gpv f (\x. x) gpv) = outs_gpv \ gpv" by(auto simp add: map_gpv_conv_bind id_def) lemma outs'_gpv_bind_option [simp]: "outs'_gpv (monad.bind_option Fail x f) = (\y\set_option x. outs'_gpv (f y))" by(cases x) simp_all lemma WT_gpv_outs_gpv: assumes "\ \g gpv \" shows "outs_gpv \ gpv \ outs_\ \" proof show "x \ outs_\ \" if "x \ outs_gpv \ gpv" for x using that assms by(induction)(blast intro: WT_gpv_OutD WT_gpv_ContD)+ qed context includes \.lifting begin lift_definition map_\ :: "('out' \ 'out) \ ('in \ 'in') \ ('out, 'in) \ \ ('out', 'in') \" is "\f g resp x. g ` resp (f x)" . lemma outs_\_map_\ [simp]: "outs_\ (map_\ f g \) = f -` outs_\ \" by transfer simp lemma responses_\_map_\ [simp]: "responses_\ (map_\ f g \) x = g ` responses_\ \ (f x)" by transfer simp lemma map_\_\_uniform [simp]: "map_\ f g (\_uniform A B) = \_uniform (f -` A) (g ` B)" by transfer(auto simp add: fun_eq_iff) lemma map_\_id [simp]: "map_\ id id \ = \" by transfer simp lemma map_\_id0: "map_\ id id = id" by(simp add: fun_eq_iff) lemma map_\_comp [simp]: "map_\ f g (map_\ f' g' \) = map_\ (f' \ f) (g \ g') \" by transfer auto lemma map_\_cong: "map_\ f g \ = map_\ f' g' \'" if "\ = \'" and f: "f = f'" and "\x y. \ x \ outs_\ \'; y \ responses_\ \' x \ \ g y = g' y" unfolding that(1,2) using that(3-) by transfer(auto simp add: fun_eq_iff intro!: image_cong) lifting_update \.lifting lifting_forget \.lifting end functor map_\ by(simp_all add: fun_eq_iff) lemma WT_gpv_map_gpv': "\ \g map_gpv' f g h gpv \" if "map_\ g h \ \g gpv \" using that by(coinduction arbitrary: gpv)(auto 4 4 dest: WT_gpvD) lemma WT_gpv_map_gpv: "\ \g map_gpv f g gpv \" if "map_\ g id \ \g gpv \" unfolding map_gpv_conv_map_gpv' using that by(rule WT_gpv_map_gpv') lemma results_gpv_map_gpv' [simp]: "results_gpv \ (map_gpv' f g h gpv) = f ` (results_gpv (map_\ g h \) gpv)" proof(intro Set.set_eqI iffI; (elim imageE; hypsubst)?) show "x \ f ` results_gpv (map_\ g h \) gpv" if "x \ results_gpv \ (map_gpv' f g h gpv)" for x using that by(induction gpv'\"map_gpv' f g h gpv" arbitrary: gpv)(fastforce intro: results_gpv.intros rev_image_eqI)+ show "f x \ results_gpv \ (map_gpv' f g h gpv)" if "x \ results_gpv (map_\ g h \) gpv" for x using that by(induction)(fastforce intro: results_gpv.intros)+ qed lemma map_\_plus_\ [simp]: "map_\ (map_sum f1 f2) (map_sum g1 g2) (\1 \\<^sub>\ \2) = map_\ f1 g1 \1 \\<^sub>\ map_\ f2 g2 \2" proof(rule \_eqI[OF Set.set_eqI], goal_cases) case (1 x) then show ?case by(cases x) auto qed (auto simp add: image_image) lemma le_plus_\_iff [simp]: "\1 \\<^sub>\ \2 \ \1' \\<^sub>\ \2' \ \1 \ \1' \ \2 \ \2'" by(auto 4 4 simp add: le_\_def dest: bspec[where x="Inl _"] bspec[where x="Inr _"]) inductive pred_gpv' :: "('a \ bool) \ ('out \ bool) \ 'in set \ ('a, 'out, 'in) gpv \ bool" for P Q X gpv where "pred_gpv' P Q X gpv" if "\x. x \ results_gpv (\_uniform UNIV X) gpv \ P x" "\out. out \ outs_gpv (\_uniform UNIV X) gpv \ Q out" lemma pred_gpv_conv_pred_gpv': "pred_gpv P Q = pred_gpv' P Q UNIV" by(auto simp add: fun_eq_iff pred_gpv_def pred_gpv'.simps results_gpv_\_full outs_gpv_\_full) lemma rel_gpv''_Grp: includes lifting_syntax shows "rel_gpv'' (BNF_Def.Grp A f) (BNF_Def.Grp B g) (BNF_Def.Grp UNIV h)\\ = BNF_Def.Grp {x. results_gpv (\_uniform UNIV (range h)) x \ A \ outs_gpv (\_uniform UNIV (range h)) x \ B} (map_gpv' f g h)" (is "?lhs = ?rhs") proof(intro ext GrpI iffI CollectI conjI subsetI) let ?\ = "\_uniform UNIV (range h)" fix gpv gpv' assume *: "?lhs gpv gpv'" then show "map_gpv' f g h gpv = gpv'" by(coinduction arbitrary: gpv gpv') (drule rel_gpv''D , auto 4 5 simp add: spmf_rel_map generat.rel_map elim!: rel_spmf_mono generat.rel_mono_strong GrpE intro!: GrpI dest: rel_funD) show "x \ A" if "x \ results_gpv ?\ gpv" for x using that * proof(induction arbitrary: gpv') case (Pure gpv) have "pred_spmf (Domainp (rel_generat (BNF_Def.Grp A f) (BNF_Def.Grp B g) ((BNF_Def.Grp UNIV h)\\ ===> rel_gpv'' (BNF_Def.Grp A f) (BNF_Def.Grp B g) (BNF_Def.Grp UNIV h)\\))) (the_gpv gpv)" using Pure.prems[THEN rel_gpv''D] unfolding spmf_Domainp_rel[symmetric] by(rule DomainPI) with Pure.hyps show ?case by(simp add: generat.Domainp_rel pred_spmf_def pred_generat_def Domainp_Grp) next case (IO out c gpv input) have "pred_spmf (Domainp (rel_generat (BNF_Def.Grp A f) (BNF_Def.Grp B g) ((BNF_Def.Grp UNIV h)\\ ===> rel_gpv'' (BNF_Def.Grp A f) (BNF_Def.Grp B g) (BNF_Def.Grp UNIV h)\\))) (the_gpv gpv)" using IO.prems[THEN rel_gpv''D] unfolding spmf_Domainp_rel[symmetric] by(rule DomainPI) with IO.hyps show ?case by(auto simp add: generat.Domainp_rel pred_spmf_def pred_generat_def Grp_iff dest: rel_funD intro: IO.IH dest!: bspec) qed show "x \ B" if "x \ outs_gpv ?\ gpv" for x using that * proof(induction arbitrary: gpv') case (IO c gpv) have "pred_spmf (Domainp (rel_generat (BNF_Def.Grp A f) (BNF_Def.Grp B g) ((BNF_Def.Grp UNIV h)\\ ===> rel_gpv'' (BNF_Def.Grp A f) (BNF_Def.Grp B g) (BNF_Def.Grp UNIV h)\\))) (the_gpv gpv)" using IO.prems[THEN rel_gpv''D] unfolding spmf_Domainp_rel[symmetric] by(rule DomainPI) with IO.hyps show ?case by(simp add: generat.Domainp_rel pred_spmf_def pred_generat_def Domainp_Grp) next case (Cont out rpv gpv input) have "pred_spmf (Domainp (rel_generat (BNF_Def.Grp A f) (BNF_Def.Grp B g) ((BNF_Def.Grp UNIV h)\\ ===> rel_gpv'' (BNF_Def.Grp A f) (BNF_Def.Grp B g) (BNF_Def.Grp UNIV h)\\))) (the_gpv gpv)" using Cont.prems[THEN rel_gpv''D] unfolding spmf_Domainp_rel[symmetric] by(rule DomainPI) with Cont.hyps show ?case by(auto simp add: generat.Domainp_rel pred_spmf_def pred_generat_def Grp_iff dest: rel_funD intro: Cont.IH dest!: bspec) qed next fix gpv gpv' assume "?rhs gpv gpv'" then have gpv': "gpv' = map_gpv' f g h gpv" and *: "results_gpv (\_uniform UNIV (range h)) gpv \ A" "outs_gpv (\_uniform UNIV (range h)) gpv \ B" by(auto simp add: Grp_iff) show "?lhs gpv gpv'" using * unfolding gpv' by(coinduction arbitrary: gpv) (fastforce simp add: spmf_rel_map generat.rel_map Grp_iff intro!: rel_spmf_reflI generat.rel_refl_strong rel_funI elim!: generat.set_cases intro: results_gpv.intros outs_gpv.intros) qed lemma rel_gpv''_map_gpv'1: "rel_gpv'' A C (BNF_Def.Grp UNIV h)\\ gpv gpv' \ rel_gpv'' A C (=) (map_gpv' id id h gpv) gpv'" apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(simp add: spmf_rel_map) apply(erule rel_spmf_mono) apply(simp add: generat.rel_map) apply(erule generat.rel_mono_strong; simp?) apply(subst map_fun2_id) by(auto simp add: rel_fun_comp intro!: rel_fun_map_fun1 elim: rel_fun_mono) lemma rel_gpv''_map_gpv'2: "rel_gpv'' A C (eq_on (range h)) gpv gpv' \ rel_gpv'' A C (BNF_Def.Grp UNIV h)\\ gpv (map_gpv' id id h gpv')" apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(simp add: spmf_rel_map) apply(erule rel_spmf_mono_strong) apply(simp add: generat.rel_map) apply(erule generat.rel_mono_strong; simp?) apply(subst map_fun_id2_in) apply(rule rel_fun_map_fun2) by (auto simp add: rel_fun_comp elim: rel_fun_mono) context fixes A :: "'a \ 'd \ bool" and C :: "'c \ 'g \ bool" and R :: "'b \ 'e \ bool" begin private lemma f11:" Pure x \ set_spmf (the_gpv gpv) \ Domainp (rel_generat A C (rel_fun R (rel_gpv'' A C R))) (Pure x) \ Domainp A x" by (auto simp add: pred_generat_def elim:bspec dest: generat.Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]) private lemma f21: "IO out c \ set_spmf (the_gpv gpv) \ rel_generat A C (rel_fun R (rel_gpv'' A C R)) (IO out c) ba \ Domainp C out" by (auto simp add: pred_generat_def elim:bspec dest: generat.Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]) private lemma f12: assumes "IO out c \ set_spmf (the_gpv gpv)" and "input \ responses_\ (\_uniform UNIV {x. Domainp R x}) out" and "x \ results_gpv (\_uniform UNIV {x. Domainp R x}) (c input)" and "Domainp (rel_gpv'' A C R) gpv" shows "Domainp (rel_gpv'' A C R) (c input)" proof - obtain b1 where o1:"rel_gpv'' A C R gpv b1" using assms(4) by clarsimp obtain b2 where o2:"rel_generat A C (rel_fun R (rel_gpv'' A C R)) (IO out c) b2" using assms(1) o1[THEN rel_gpv''D, THEN spmf_Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]] unfolding pred_spmf_def by - (drule (1) bspec, auto) have "Ball (generat_conts (IO out c)) (Domainp (rel_fun R (rel_gpv'' A C R)))" using o2[THEN generat.Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]] unfolding pred_generat_def by simp with assms(2) show ?thesis apply - apply(drule bspec) apply simp apply clarify apply(drule Domainp_rel_fun_le[THEN predicate1D, OF Domainp_iff[THEN iffD2], OF exI]) by simp qed private lemma f22: assumes "IO out' rpv \ set_spmf (the_gpv gpv)" and "input \ responses_\ (\_uniform UNIV {x. Domainp R x}) out'" and "out \ outs_gpv (\_uniform UNIV {x. Domainp R x}) (rpv input)" and "Domainp (rel_gpv'' A C R) gpv" shows "Domainp (rel_gpv'' A C R) (rpv input)" proof - obtain b1 where o1:"rel_gpv'' A C R gpv b1" using assms(4) by auto obtain b2 where o2:"rel_generat A C (rel_fun R (rel_gpv'' A C R)) (IO out' rpv) b2" using assms(1) o1[THEN rel_gpv''D, THEN spmf_Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]] unfolding pred_spmf_def by - (drule (1) bspec, auto) have "Ball (generat_conts (IO out' rpv)) (Domainp (rel_fun R (rel_gpv'' A C R)))" using o2[THEN generat.Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]] unfolding pred_generat_def by simp with assms(2) show ?thesis apply - apply(drule bspec) apply simp apply clarify apply(drule Domainp_rel_fun_le[THEN predicate1D, OF Domainp_iff[THEN iffD2], OF exI]) by simp qed lemma Domainp_rel_gpv''_le: "Domainp (rel_gpv'' A C R) \ pred_gpv' (Domainp A) (Domainp C) {x. Domainp R x}" proof(rule predicate1I pred_gpv'.intros)+ show "Domainp A x" if "x \ results_gpv (\_uniform UNIV {x. Domainp R x}) gpv" "Domainp (rel_gpv'' A C R) gpv" for x gpv using that proof(induction) case (Pure gpv) then show ?case by (clarify) (drule rel_gpv''D , auto simp add: f11 pred_spmf_def dest: spmf_Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]) qed (simp add: f12) show "Domainp C out" if "out \ outs_gpv (\_uniform UNIV {x. Domainp R x}) gpv" "Domainp (rel_gpv'' A C R) gpv" for out gpv using that proof( induction) case (IO c gpv) then show ?case by (clarify) (drule rel_gpv''D , auto simp add: f21 pred_spmf_def dest!: bspec spmf_Domainp_rel[THEN fun_cong, THEN iffD1, OF Domainp_iff[THEN iffD2], OF exI]) qed (simp add: f22) qed end lemma map_gpv'_id12: "map_gpv' f g h gpv = map_gpv' id id h (map_gpv f g gpv)" unfolding map_gpv_conv_map_gpv' map_gpv'_comp by simp lemma rel_gpv''_refl: "\ (=) \ A; (=) \ C; R \ (=) \ \ (=) \ rel_gpv'' A C R" by(subst rel_gpv''_eq[symmetric])(rule rel_gpv''_mono) context fixes A A' :: "'a \ 'b \ bool" and C C' :: "'c \ 'd \ bool" and R R' :: "'e \ 'f \ bool" begin private abbreviation foo where "foo \ (\ fx fy gpvx gpvy g1 g2. \x y. x \ fx (\_uniform UNIV (Collect (Domainp R'))) gpvx \ y \ fy (\_uniform UNIV (Collect (Rangep R'))) gpvy \ g1 x y \ g2 x y)" private lemma f1: "foo results_gpv results_gpv gpv gpv' A A' \ x \ set_spmf (the_gpv gpv) \ y \ set_spmf (the_gpv gpv') \ a \ generat_conts x \ b \ generat_conts y \ R' a' \ \ R' \ b' \ foo results_gpv results_gpv (a a') (b b') A A'" by (fastforce elim: generat.set_cases intro: results_gpv.IO) private lemma f2: "foo outs_gpv outs_gpv gpv gpv' C C' \ x \ set_spmf (the_gpv gpv) \ y \ set_spmf (the_gpv gpv') \ a \ generat_conts x \ b \ generat_conts y \ R' a' \ \ R' \ b' \ foo outs_gpv outs_gpv (a a') (b b') C C'" by (fastforce elim: generat.set_cases intro: outs_gpv.Cont) lemma rel_gpv''_mono_strong: "\ rel_gpv'' A C R gpv gpv'; \x y. \ x \ results_gpv (\_uniform UNIV {x. Domainp R' x}) gpv; y \ results_gpv (\_uniform UNIV {x. Rangep R' x}) gpv'; A x y \ \ A' x y; \x y. \ x \ outs_gpv (\_uniform UNIV {x. Domainp R' x}) gpv; y \ outs_gpv (\_uniform UNIV {x. Rangep R' x}) gpv'; C x y \ \ C' x y; R' \ R \ \ rel_gpv'' A' C' R' gpv gpv'" apply(coinduction arbitrary: gpv gpv') apply(drule rel_gpv''D) apply(erule rel_spmf_mono_strong) apply(erule generat.rel_mono_strong) apply(erule generat.set_cases)+ apply(erule allE, rotate_tac -1) apply(erule allE) apply(erule impE) apply(rule results_gpv.Pure) apply simp apply(erule impE) apply(rule results_gpv.Pure) apply simp apply simp apply(erule generat.set_cases)+ apply(rotate_tac 1) apply(erule allE, rotate_tac -1) apply(erule allE) apply(erule impE) apply(rule outs_gpv.IO) apply simp apply(erule impE) apply(rule outs_gpv.IO) apply simp apply simp apply(erule (1) rel_fun_mono_strong) by (fastforce simp add: f1[simplified] f2[simplified]) end lemma rel_gpv''_refl_strong: assumes "\x. x \ results_gpv (\_uniform UNIV {x. Domainp R x}) gpv \ A x x" and "\x. x \ outs_gpv (\_uniform UNIV {x. Domainp R x}) gpv \ C x x" and "R \ (=)" shows "rel_gpv'' A C R gpv gpv" proof - have "rel_gpv'' (=) (=) (=) gpv gpv" unfolding rel_gpv''_eq by simp then show ?thesis using _ _ assms(3) by(rule rel_gpv''_mono_strong)(auto intro: assms(1-2)) qed lemma rel_gpv''_refl_eq_on: "\ \x. x \ results_gpv (\_uniform UNIV X) gpv \ A x x; \out. out \ outs_gpv (\_uniform UNIV X) gpv \ B out out \ \ rel_gpv'' A B (eq_on X) gpv gpv" by(rule rel_gpv''_refl_strong) (auto elim: eq_onE) lemma pred_gpv'_mono' [mono]: "pred_gpv' A C R gpv \ pred_gpv' A' C' R gpv" if "\x. A x \ A' x" "\x. C x \ C' x" using that unfolding pred_gpv'.simps by auto primcorec enforce_\_gpv :: "('out, 'in) \ \ ('a, 'out, 'in) gpv \ ('a, 'out, 'in) gpv" where "enforce_\_gpv \ gpv = GPV (map_spmf (map_generat id id ((\) (enforce_\_gpv \))) (map_spmf (\generat. case generat of Pure x \ Pure x | IO out rpv \ IO out (\input. if input \ responses_\ \ out then rpv input else Fail)) (enforce_spmf (pred_generat \ (\x. x \ outs_\ \) \) (the_gpv gpv))))" lemma enforce_\_gpv_Done [simp]: "enforce_\_gpv \ (Done x) = Done x" by(rule gpv.expand) simp lemma enforce_\_gpv_Fail [simp]: "enforce_\_gpv \ Fail = Fail" by(rule gpv.expand) simp lemma enforce_\_gpv_Pause [simp]: "enforce_\_gpv \ (Pause out rpv) = (if out \ outs_\ \ then Pause out (\input. if input \ responses_\ \ out then enforce_\_gpv \ (rpv input) else Fail) else Fail)" by(rule gpv.expand)(simp add: fun_eq_iff) lemma enforce_\_gpv_lift_spmf [simp]: "enforce_\_gpv \ (lift_spmf p) = lift_spmf p" by(rule gpv.expand)(simp add: enforce_map_spmf spmf.map_comp o_def) lemma enforce_\_gpv_bind_gpv [simp]: "enforce_\_gpv \ (bind_gpv gpv f) = bind_gpv (enforce_\_gpv \ gpv) (enforce_\_gpv \ \ f)" by(coinduction arbitrary: gpv rule: gpv.coinduct_strong) (auto 4 3 simp add: bind_gpv.sel spmf_rel_map bind_map_spmf o_def pred_generat_def elim!: generat.set_cases intro!: generat.rel_refl_strong rel_spmf_bind_reflI rel_spmf_reflI rel_funI split!: if_splits generat.split_asm) lemma enforce_\_gpv_parametric': includes lifting_syntax notes [transfer_rule] = corec_gpv_parametric' the_gpv_parametric' Fail_parametric' assumes [transfer_rule]: "bi_unique C" "bi_unique R" shows "(rel_\ C R ===> rel_gpv'' A C R ===> rel_gpv'' A C R) enforce_\_gpv enforce_\_gpv" unfolding enforce_\_gpv_def top_fun_def by(transfer_prover) lemma enforce_\_gpv_parametric [transfer_rule]: includes lifting_syntax shows "bi_unique C \ (rel_\ C (=) ===> rel_gpv A C ===> rel_gpv A C) enforce_\_gpv enforce_\_gpv" unfolding rel_gpv_conv_rel_gpv'' by(rule enforce_\_gpv_parametric'[OF _ bi_unique_eq]) lemma WT_enforce_\_gpv [simp]: "\ \g enforce_\_gpv \ gpv \" by(coinduction arbitrary: gpv)(auto split: generat.split_asm) lemma WT_gpv_parametric': includes lifting_syntax shows "bi_unique C \ (rel_\ C R ===> rel_gpv'' A C R ===> (=)) WT_gpv WT_gpv" proof(rule rel_funI iffI)+ note [transfer_rule] = the_gpv_parametric' show *: "\ \g gpv \" if [transfer_rule]: "rel_\ C R \ \'" "bi_unique C" and *: "\' \g gpv' \" "rel_gpv'' A C R gpv gpv'" for \ \' gpv gpv' A C R using * proof(coinduction arbitrary: gpv gpv') case (WT_gpv out c gpv gpv') note [transfer_rule] = WT_gpv(2) have "rel_set (rel_generat A C (R ===> rel_gpv'' A C R)) (set_spmf (the_gpv gpv)) (set_spmf (the_gpv gpv'))" by transfer_prover from rel_setD1[OF this WT_gpv(3)] obtain out' c' where [transfer_rule]: "C out out'" "(R ===> rel_gpv'' A C R) c c'" and out': "IO out' c' \ set_spmf (the_gpv gpv')" by(auto elim: generat.rel_cases) have "out \ outs_\ \ \ out' \ outs_\ \'" by transfer_prover with WT_gpvD(1)[OF WT_gpv(1) out'] have ?out by simp moreover have ?cont proof(standard; goal_cases cont) case (cont input) have "rel_set R (responses_\ \ out) (responses_\ \' out')" by transfer_prover from rel_setD1[OF this cont] obtain input' where [transfer_rule]: "R input input'" and input': "input' \ responses_\ \' out'" by blast have "rel_gpv'' A C R (c input) (c' input')" by transfer_prover with WT_gpvD(2)[OF WT_gpv(1) out' input'] show ?case by auto qed ultimately show ?case .. qed show "\' \g gpv' \" if "rel_\ C R \ \'" "bi_unique C" "\ \g gpv \" "rel_gpv'' A C R gpv gpv'" for \ \' gpv gpv' using *[of "conversep C" "conversep R" \' \ gpv "conversep A" gpv'] that by(simp add: rel_gpv''_conversep) qed lemma WT_gpv_map_gpv_id [simp]: "\ \g map_gpv f id gpv \ \ \ \g gpv \" using WT_gpv_parametric'[of "BNF_Def.Grp UNIV id" "(=)" "BNF_Def.Grp UNIV f", folded rel_gpv_conv_rel_gpv''] unfolding gpv.rel_Grp unfolding eq_alt[symmetric] relator_eq by(auto simp add: rel_fun_def Grp_def bi_unique_eq) locale raw_converter_invariant = fixes \ :: "('call, 'ret) \" and \' :: "('call', 'ret') \" and callee :: "'s \ 'call \ ('ret \ 's, 'call', 'ret') gpv" and I :: "'s \ bool" assumes results_callee: "\s x. \ x \ outs_\ \; I s \ \ results_gpv \' (callee s x) \ responses_\ \ x \ {s. I s}" and WT_callee: "\x s. \ x \ outs_\ \; I s \ \ \' \g callee s x \" begin context begin private lemma aux: "set_spmf (inline1 callee gpv s) \ {Inr (out, callee', rpv') | out callee' rpv'. \call\outs_\ \. \s. I s \ (\x \ responses_\ \' out. callee' x \ sub_gpvs \' (callee s call))} \ {Inl (x, s') | x s'. x \ results_gpv \ gpv \ I s'}" (is "?concl (inline1 callee) gpv s" is "_ \ ?rhs1 \ ?rhs2 gpv") if "\ \g gpv \" "I s" using that proof(induction arbitrary: gpv s rule: inline1_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case (step inline1') { fix out c assume IO: "IO out c \ set_spmf (the_gpv gpv)" from step.prems(1) IO have out: "out \ outs_\ \" by(rule WT_gpvD) { fix x s' assume Pure: "Pure (x, s') \ set_spmf (the_gpv (callee s out))" then have "(x, s') \ results_gpv \' (callee s out)" by(rule results_gpv.Pure) with out step.prems(2) have "x \ responses_\ \ out" "I s'" by(auto dest: results_callee) from step.prems(1) IO this(1) have "\ \g c x \" by(rule WT_gpvD) hence "?concl inline1' (c x) s'" using \I s'\ by(rule step.IH) also have "\ \ ?rhs1 \ ?rhs2 gpv" using \x \ _\ IO by(auto intro: results_gpv.intros) also note calculation } moreover { fix out' c' assume "IO out' c' \ set_spmf (the_gpv (callee s out))" hence "\x\responses_\ \' out'. c' x \ sub_gpvs \' (callee s out)" by(auto intro: sub_gpvs.base) then have "\call\outs_\ \. \s. I s \ (\x\responses_\ \' out'. c' x \ sub_gpvs \' (callee s call))" using out step.prems(2) by blast } moreover note calculation } then show ?case using step.prems by(auto 4 3 del: subsetI simp add: bind_UNION intro!: UN_least split: generat.split intro: results_gpv.intros) qed lemma inline1_in_sub_gpvs_callee: assumes "Inr (out, callee', rpv') \ set_spmf (inline1 callee gpv s)" and WT: "\ \g gpv \" and s: "I s" shows "\call\outs_\ \. \s. I s \ (\x \ responses_\ \' out. callee' x \ sub_gpvs \' (callee s call))" using aux[OF WT s] assms(1) by fastforce lemma inline1_Inl_results_gpv: assumes "Inl (x, s') \ set_spmf (inline1 callee gpv s)" and WT: "\ \g gpv \" and s: "I s" shows "x \ results_gpv \ gpv \ I s'" using aux[OF WT s] assms(1) by fastforce end lemma inline1_in_sub_gpvs: assumes "Inr (out, callee', rpv') \ set_spmf (inline1 callee gpv s)" and "(x, s') \ results_gpv \' (callee' input)" and "input \ responses_\ \' out" and "\ \g gpv \" and "I s" shows "rpv' x \ sub_gpvs \ gpv \ I s'" proof - from \\ \g gpv \\ \I s\ have "set_spmf (inline1 callee gpv s) \ {Inr (out, callee', rpv') | out callee' rpv'. \input \ responses_\ \' out. \(x, s')\results_gpv \' (callee' input). I s' \ rpv' x \ sub_gpvs \ gpv} \ {Inl (x, s') | x s'. I s'}" (is "?concl (inline1 callee) gpv s" is "_ \ ?rhs gpv s") proof(induction arbitrary: gpv s rule: inline1_fixp_induct) case adm show ?case by(intro cont_intro ccpo_class.admissible_leI) case bottom show ?case by simp case (step inline1') { fix out c assume IO: "IO out c \ set_spmf (the_gpv gpv)" from step.prems(1) IO have out: "out \ outs_\ \" by(rule WT_gpvD) { fix x s' assume Pure: "Pure (x, s') \ set_spmf (the_gpv (callee s out))" then have "(x, s') \ results_gpv \' (callee s out)" by(rule results_gpv.Pure) with out step.prems(2) have "x \ responses_\ \ out" "I s'" by(auto dest: results_callee) from step.prems(1) IO this(1) have "\ \g c x \" by(rule WT_gpvD) hence "?concl inline1' (c x) s'" using \I s'\ by(rule step.IH) also have "\ \ ?rhs gpv s'" using IO Pure \I s\ by(fastforce intro: sub_gpvs.cont dest: WT_gpv_OutD[OF step.prems(1)] results_callee[THEN subsetD, OF _ _ results_gpv.Pure]) finally have "set_spmf (inline1' (c x) s') \ \" . } moreover { fix out' c' input x s' assume "IO out' c' \ set_spmf (the_gpv (callee s out))" and "input \ responses_\ \' out'" and "(x, s') \ results_gpv \' (c' input)" then have "c x \ sub_gpvs \ gpv" "I s'" using IO \I s\ by(auto intro!: sub_gpvs.base dest: WT_gpv_OutD[OF step.prems(1)] results_callee[THEN subsetD, OF _ _ results_gpv.IO]) } moreover note calculation } then show ?case using step.prems(2) by(auto simp add: bind_UNION intro!: UN_least split: generat.split del: subsetI) qed with assms show ?thesis by fastforce qed lemma WT_gpv_inline1: assumes "Inr (out, rpv, rpv') \ set_spmf (inline1 callee gpv s)" and "\ \g gpv \" and "I s" shows "out \ outs_\ \'" (is "?thesis1") and "input \ responses_\ \' out \ \' \g rpv input \" (is "PROP ?thesis2") and "\ input \ responses_\ \' out; (x, s') \ results_gpv \' (rpv input) \ \ \ \g rpv' x \ \ I s'" (is "PROP ?thesis3") proof - from \\ \g gpv \\ \I s\ have "set_spmf (inline1 callee gpv s) \ {Inr (out, rpv, rpv') | out rpv rpv'. out \ outs_\ \'} \ {Inl (x, s')| x s'. I s'}" proof(induction arbitrary: gpv s rule: inline1_fixp_induct) { case adm show ?case by(intro cont_intro ccpo_class.admissible_leI) } { case bottom show ?case by simp } case (step inline1') { fix out c assume IO: "IO out c \ set_spmf (the_gpv gpv)" from step.prems(1) IO have out: "out \ outs_\ \" by(rule WT_gpvD) { fix x s' assume Pure: "Pure (x, s') \ set_spmf (the_gpv (callee s out))" then have *: "(x, s') \ results_gpv \' (callee s out)" by(rule results_gpv.Pure) with out step.prems(2) have "x \ responses_\ \ out" "I s'" by(auto dest: results_callee) from step.prems(1) IO this(1) have "\ \g c x \" by(rule WT_gpvD) note this \I s'\ } moreover { fix out' c' from out step.prems(2) have "\' \g callee s out \" by(rule WT_callee) moreover assume "IO out' c' \ set_spmf (the_gpv (callee s out))" ultimately have "out' \ outs_\ \'" by(rule WT_gpvD) } moreover note calculation } then show ?case using step.prems(2) by(auto del: subsetI simp add: bind_UNION intro!: UN_least split: generat.split intro!: step.IH[THEN order_trans]) qed then show ?thesis1 using assms by auto assume "input \ responses_\ \' out" with inline1_in_sub_gpvs_callee[OF \Inr _ \ _\ \\ \g gpv \\ \I s\] obtain out' s where "out' \ outs_\ \" and *: "rpv input \ sub_gpvs \' (callee s out')" and "I s" by blast from \out' \ _\ \I s\ have "\' \g callee s out' \" by(rule WT_callee) then show "\' \g rpv input \" using * by(rule WT_sub_gpvsD) assume "(x, s') \ results_gpv \' (rpv input)" with \Inr _ \ _\ have "rpv' x \ sub_gpvs \ gpv \ I s'" using \input \ _\ \\ \g gpv \\ assms(3) \I s\ by-(rule inline1_in_sub_gpvs) with \\ \g gpv \\ show "\ \g rpv' x \ \ I s'" by(blast intro: WT_sub_gpvsD) qed lemma WT_gpv_inline_invar: assumes "\ \g gpv \" and "I s" shows "\' \g inline callee gpv s \" using assms proof(coinduction arbitrary: gpv s rule: WT_gpv_coinduct_bind) case (WT_gpv out c gpv) from \IO out c \ _\ obtain callee' rpv' where Inr: "Inr (out, callee', rpv') \ set_spmf (inline1 callee gpv s)" and c: "c = (\input. callee' input \ (\(x, s). inline callee (rpv' x) s))" by(clarsimp simp add: inline_sel split: sum.split_asm) from Inr \\ \g gpv \\ \I s\ have ?out by(rule WT_gpv_inline1) moreover have "?cont TYPE('ret \ 's)" (is "\input\_. _ \ _ \ ?case' input") proof(rule ballI disjI2)+ fix input assume "input \ responses_\ \' out" with Inr \\ \g gpv \ \ \I s\ have "\' \g callee' input \" and "\x s'. (x, s') \ results_gpv \' (callee' input) \ \ \g rpv' x \ \ I s'" by(blast dest: WT_gpv_inline1)+ then show "?case' input" by(subst c)(auto 4 5) qed ultimately show "?case TYPE('ret \ 's)" .. qed end lemma WT_gpv_inline: assumes "\s x. x \ outs_\ \ \ results_gpv \' (callee s x) \ responses_\ \ x \ UNIV" and "\x s. x \ outs_\ \ \ \' \g callee s x \" and "\ \g gpv \" shows "\' \g inline callee gpv s \" proof - interpret raw_converter_invariant \ \' callee "\_. True" using assms by(unfold_locales)auto show ?thesis by(rule WT_gpv_inline_invar)(use assms in auto) qed lemma results_gpv_sub_gvps: "gpv' \ sub_gpvs \ gpv \ results_gpv \ gpv' \ results_gpv \ gpv" by(induction rule: sub_gpvs.induct)(auto intro: results_gpv.IO) lemma in_results_gpv_sub_gvps: "\ x \ results_gpv \ gpv'; gpv' \ sub_gpvs \ gpv \ \ x \ results_gpv \ gpv" using results_gpv_sub_gvps[of gpv' \ gpv] by blast context raw_converter_invariant begin lemma results_gpv_inline_aux: assumes "(x, s') \ results_gpv \' (inline_aux callee y)" shows "\ y = Inl (gpv, s); \ \g gpv \; I s \ \ x \ results_gpv \ gpv \ I s'" and "\ y = Inr (rpv, callee'); \(z, s') \ results_gpv \' callee'. \ \g rpv z \ \ I s' \ \ \(z, s'') \ results_gpv \' callee'. x \ results_gpv \ (rpv z) \ I s'' \ I s'" using assms proof(induction gvp'\"inline_aux callee y" arbitrary: y gpv s rpv callee') case Pure case 1 with Pure show ?case by(auto simp add: inline_aux.sel split: sum.split_asm dest: inline1_Inl_results_gpv) next case Pure case 2 with Pure show ?case by(clarsimp simp add: inline_aux.sel split: sum.split_asm) (fastforce split: generat.split_asm dest: inline1_Inl_results_gpv intro: results_gpv.Pure)+ next case (IO out c input) case 1 with IO(1) obtain rpv rpv' where inline1: "Inr (out, rpv, rpv') \ set_spmf (inline1 callee gpv s)" and c: "c = (\input. inline_aux callee (Inr (rpv', rpv input)))" by(auto simp add: inline_aux.sel split: sum.split_asm) from inline1[THEN inline1_in_sub_gpvs, OF _ \input \ responses_\ \' out\ _ \I s\] \\ \g gpv \\ have "\(z, s')\results_gpv \' (rpv input). \ \g rpv' z \ \ I s'" by(auto intro: WT_sub_gpvsD) from IO(5)[unfolded c, OF refl refl this] obtain input' s'' where input': "(input', s'') \ results_gpv \' (rpv input)" and x: "x \ results_gpv \ (rpv' input')" and s'': "I s''" "I s'" by auto from inline1[THEN inline1_in_sub_gpvs, OF input' \input \ responses_\ \' out\ \\ \g gpv \\ \I s\] s'' x show ?case by(auto intro: in_results_gpv_sub_gvps) next case (IO out c input) case 2 from IO(1) "2"(1) consider (Pure) input' s'' rpv' rpv'' where "Pure (input', s'') \ set_spmf (the_gpv callee')" "Inr (out, rpv', rpv'') \ set_spmf (inline1 callee (rpv input') s'')" "c = (\input. inline_aux callee (Inr (rpv'', rpv' input)))" | (Cont) rpv' where "IO out rpv' \ set_spmf (the_gpv callee')" "c = (\input. inline_aux callee (Inr (rpv, rpv' input)))" by(auto simp add: inline_aux.sel split: sum.split_asm; rename_tac generat; case_tac generat; clarsimp) then show ?case proof cases case Pure have res: "(input', s'') \ results_gpv \' callee'" using Pure(1) by(rule results_gpv.Pure) with 2 have WT: "\ \g rpv input' \" "I s''" by auto have "\(z, s')\results_gpv \' (rpv' input). \ \g rpv'' z \ \ I s'" using inline1_in_sub_gpvs[OF Pure(2) _ \input \ _\ WT] WT by(auto intro: WT_sub_gpvsD) from IO(5)[unfolded Pure(3), OF refl refl this] obtain z s''' where z: "(z, s''') \ results_gpv \' (rpv' input)" and x: "x \ results_gpv \ (rpv'' z)" and s': "I s'''" "I s'" by auto have "x \ results_gpv \ (rpv input')" using x inline1_in_sub_gpvs[OF Pure(2) z \input \ _\ WT] by(auto intro: in_results_gpv_sub_gvps) then show ?thesis using res WT s' by auto next case Cont have "\(z, s')\results_gpv \' (rpv' input). \ \g rpv z \ \ I s'" using Cont 2 \input \ responses_\ \' out\ by(auto intro: results_gpv.IO) from IO(5)[unfolded Cont, OF refl refl this] obtain z s'' where "(z, s'') \ results_gpv \' (rpv' input)" "x \ results_gpv \ (rpv z)" "I s''" "I s'" by auto then show ?thesis using Cont(1) \input \ _\ by(auto intro: results_gpv.IO) qed qed lemma results_gpv_inline: "\(x, s') \ results_gpv \' (inline callee gpv s); \ \g gpv \; I s\ \ x \ results_gpv \ gpv \ I s'" unfolding inline_def by(rule results_gpv_inline_aux(1)[OF _ refl]) end lemma inline_map_gpv: "inline callee (map_gpv f g gpv) s = map_gpv (apfst f) id (inline (\s x. callee s (g x)) gpv s)" unfolding apfst_def by(rule inline_parametric [where S="BNF_Def.Grp UNIV id" and C="BNF_Def.Grp UNIV g" and C'="BNF_Def.Grp UNIV id" and A="BNF_Def.Grp UNIV f", THEN rel_funD, THEN rel_funD, THEN rel_funD, unfolded gpv.rel_Grp prod.rel_Grp, simplified, folded eq_alt, unfolded Grp_def, simplified]) (auto simp add: rel_fun_def relator_eq) (* Computational_Model *) lemma \_full_le_plus_\: "\_full \ plus_\ \1 \2" if "\_full \ \1" "\_full \ \2" using that by(auto simp add: le_\_def top_unique) lemma plus_\_mono: "plus_\ \1 \2 \ plus_\ \1' \2'" if "\1 \ \1'" "\2 \ \2'" using that by(fastforce simp add: le_\_def) primcorec (transfer) left_gpv :: "('a, 'out, 'in) gpv \ ('a, 'out + 'out', 'in + 'in') gpv" where "the_gpv (left_gpv gpv) = map_spmf (map_generat id Inl (\rpv input. case input of Inl input' \ left_gpv (rpv input') | _ \ Fail)) (the_gpv gpv)" abbreviation left_rpv :: "('a, 'out, 'in) rpv \ ('a, 'out + 'out', 'in + 'in') rpv" where "left_rpv rpv \ \input. case input of Inl input' \ left_gpv (rpv input') | _ \ Fail" primcorec (transfer) right_gpv :: "('a, 'out, 'in) gpv \ ('a, 'out' + 'out, 'in' + 'in) gpv" where "the_gpv (right_gpv gpv) = map_spmf (map_generat id Inr (\rpv input. case input of Inr input' \ right_gpv (rpv input') | _ \ Fail)) (the_gpv gpv)" abbreviation right_rpv :: "('a, 'out, 'in) rpv \ ('a, 'out' + 'out, 'in' + 'in) rpv" where "right_rpv rpv \ \input. case input of Inr input' \ right_gpv (rpv input') | _ \ Fail" context includes lifting_syntax notes [transfer_rule] = corec_gpv_parametric' Fail_parametric' the_gpv_parametric' begin lemmas left_gpv_parametric = left_gpv.transfer lemma left_gpv_parametric': "(rel_gpv'' A C R ===> rel_gpv'' A (rel_sum C C') (rel_sum R R')) left_gpv left_gpv" unfolding left_gpv_def by transfer_prover lemmas right_gpv_parametric = right_gpv.transfer lemma right_gpv_parametric': "(rel_gpv'' A C' R' ===> rel_gpv'' A (rel_sum C C') (rel_sum R R')) right_gpv right_gpv" unfolding right_gpv_def by transfer_prover end lemma left_gpv_Done [simp]: "left_gpv (Done x) = Done x" by(rule gpv.expand) simp lemma right_gpv_Done [simp]: "right_gpv (Done x) = Done x" by(rule gpv.expand) simp lemma left_gpv_Pause [simp]: "left_gpv (Pause x rpv) = Pause (Inl x) (\input. case input of Inl input' \ left_gpv (rpv input') | _ \ Fail)" by(rule gpv.expand) simp lemma right_gpv_Pause [simp]: "right_gpv (Pause x rpv) = Pause (Inr x) (\input. case input of Inr input' \ right_gpv (rpv input') | _ \ Fail)" by(rule gpv.expand) simp lemma left_gpv_map: "left_gpv (map_gpv f g gpv) = map_gpv f (map_sum g h) (left_gpv gpv)" using left_gpv.transfer[of "BNF_Def.Grp UNIV f" "BNF_Def.Grp UNIV g" "BNF_Def.Grp UNIV h"] unfolding sum.rel_Grp gpv.rel_Grp by(auto simp add: rel_fun_def Grp_def) lemma right_gpv_map: "right_gpv (map_gpv f g gpv) = map_gpv f (map_sum h g) (right_gpv gpv)" using right_gpv.transfer[of "BNF_Def.Grp UNIV f" "BNF_Def.Grp UNIV g" "BNF_Def.Grp UNIV h"] unfolding sum.rel_Grp gpv.rel_Grp by(auto simp add: rel_fun_def Grp_def) lemma results'_gpv_left_gpv [simp]: "results'_gpv (left_gpv gpv :: ('a, 'out + 'out', 'in + 'in') gpv) = results'_gpv gpv" (is "?lhs = ?rhs") proof(rule Set.set_eqI iffI)+ show "x \ ?rhs" if "x \ ?lhs" for x using that by(induction gpv'\"left_gpv gpv :: ('a, 'out + 'out', 'in + 'in') gpv" arbitrary: gpv) (fastforce simp add: elim!: generat.set_cases intro: results'_gpvI split: sum.splits)+ show "x \ ?lhs" if "x \ ?rhs" for x using that by(induction) (auto 4 3 elim!: generat.set_cases intro: results'_gpv_Pure rev_image_eqI results'_gpv_Cont[where input="Inl _"]) qed lemma results'_gpv_right_gpv [simp]: "results'_gpv (right_gpv gpv :: ('a, 'out' + 'out, 'in' + 'in) gpv) = results'_gpv gpv" (is "?lhs = ?rhs") proof(rule Set.set_eqI iffI)+ show "x \ ?rhs" if "x \ ?lhs" for x using that by(induction gpv'\"right_gpv gpv :: ('a, 'out' + 'out, 'in' + 'in) gpv" arbitrary: gpv) (fastforce simp add: elim!: generat.set_cases intro: results'_gpvI split: sum.splits)+ show "x \ ?lhs" if "x \ ?rhs" for x using that by(induction) (auto 4 3 elim!: generat.set_cases intro: results'_gpv_Pure rev_image_eqI results'_gpv_Cont[where input="Inr _"]) qed lemma left_gpv_Inl_transfer: "rel_gpv'' (=) (\l r. l = Inl r) (\l r. l = Inl r) (left_gpv gpv) gpv" by(coinduction arbitrary: gpv) (auto simp add: spmf_rel_map generat.rel_map del: rel_funI intro!: rel_spmf_reflI generat.rel_refl_strong rel_funI) lemma right_gpv_Inr_transfer: "rel_gpv'' (=) (\l r. l = Inr r) (\l r. l = Inr r) (right_gpv gpv) gpv" by(coinduction arbitrary: gpv) (auto simp add: spmf_rel_map generat.rel_map del: rel_funI intro!: rel_spmf_reflI generat.rel_refl_strong rel_funI) lemma exec_gpv_plus_oracle_left: "exec_gpv (plus_oracle oracle1 oracle2) (left_gpv gpv) s = exec_gpv oracle1 gpv s" unfolding spmf_rel_eq[symmetric] prod.rel_eq[symmetric] by(rule exec_gpv_parametric'[where A="(=)" and S="(=)" and CALL="\l r. l = Inl r" and R="\l r. l = Inl r", THEN rel_funD, THEN rel_funD, THEN rel_funD]) (auto intro!: rel_funI simp add: spmf_rel_map apfst_def map_prod_def rel_prod_conv intro: rel_spmf_reflI left_gpv_Inl_transfer) lemma exec_gpv_plus_oracle_right: "exec_gpv (plus_oracle oracle1 oracle2) (right_gpv gpv) s = exec_gpv oracle2 gpv s" unfolding spmf_rel_eq[symmetric] prod.rel_eq[symmetric] by(rule exec_gpv_parametric'[where A="(=)" and S="(=)" and CALL="\l r. l = Inr r" and R="\l r. l = Inr r", THEN rel_funD, THEN rel_funD, THEN rel_funD]) (auto intro!: rel_funI simp add: spmf_rel_map apfst_def map_prod_def rel_prod_conv intro: rel_spmf_reflI right_gpv_Inr_transfer) lemma left_gpv_bind_gpv: "left_gpv (bind_gpv gpv f) = bind_gpv (left_gpv gpv) (left_gpv \ f)" by(coinduction arbitrary:gpv f rule: gpv.coinduct_strong) (auto 4 4 simp add: bind_map_spmf spmf_rel_map intro!: rel_spmf_reflI rel_spmf_bindI[of "(=)"] generat.rel_refl rel_funI split: sum.splits) lemma inline1_left_gpv: "inline1 (\s q. left_gpv (callee s q)) gpv s = map_spmf (map_sum id (map_prod Inl (map_prod left_rpv id))) (inline1 callee gpv s)" proof(induction arbitrary: gpv s rule: parallel_fixp_induct_2_2[OF partial_function_definitions_spmf partial_function_definitions_spmf inline1.mono inline1.mono inline1_def inline1_def, unfolded lub_spmf_empty, case_names adm bottom step]) case adm show ?case by simp case bottom show ?case by simp case (step inline1' inline1'') then show ?case by(auto simp add: map_spmf_bind_spmf o_def bind_map_spmf intro!: ext bind_spmf_cong split: generat.split) qed lemma left_gpv_inline: "left_gpv (inline callee gpv s) = inline (\s q. left_gpv (callee s q)) gpv s" by(coinduction arbitrary: callee gpv s rule: gpv_coinduct_bind) (fastforce simp add: inline_sel spmf_rel_map inline1_left_gpv left_gpv_bind_gpv o_def split_def intro!: rel_spmf_reflI split: sum.split intro!: rel_funI gpv.rel_refl_strong) lemma right_gpv_bind_gpv: "right_gpv (bind_gpv gpv f) = bind_gpv (right_gpv gpv) (right_gpv \ f)" by(coinduction arbitrary:gpv f rule: gpv.coinduct_strong) (auto 4 4 simp add: bind_map_spmf spmf_rel_map intro!: rel_spmf_reflI rel_spmf_bindI[of "(=)"] generat.rel_refl rel_funI split: sum.splits) lemma inline1_right_gpv: "inline1 (\s q. right_gpv (callee s q)) gpv s = map_spmf (map_sum id (map_prod Inr (map_prod right_rpv id))) (inline1 callee gpv s)" proof(induction arbitrary: gpv s rule: parallel_fixp_induct_2_2[OF partial_function_definitions_spmf partial_function_definitions_spmf inline1.mono inline1.mono inline1_def inline1_def, unfolded lub_spmf_empty, case_names adm bottom step]) case adm show ?case by simp case bottom show ?case by simp case (step inline1' inline1'') then show ?case by(auto simp add: map_spmf_bind_spmf o_def bind_map_spmf intro!: ext bind_spmf_cong split: generat.split) qed lemma right_gpv_inline: "right_gpv (inline callee gpv s) = inline (\s q. right_gpv (callee s q)) gpv s" by(coinduction arbitrary: callee gpv s rule: gpv_coinduct_bind) (fastforce simp add: inline_sel spmf_rel_map inline1_right_gpv right_gpv_bind_gpv o_def split_def intro!: rel_spmf_reflI split: sum.split intro!: rel_funI gpv.rel_refl_strong) lemma WT_gpv_left_gpv: "\1 \g gpv \ \ \1 \\<^sub>\ \2 \g left_gpv gpv \" by(coinduction arbitrary: gpv)(auto 4 4 dest: WT_gpvD) lemma WT_gpv_right_gpv: "\2 \g gpv \ \ \1 \\<^sub>\ \2 \g right_gpv gpv \" by(coinduction arbitrary: gpv)(auto 4 4 dest: WT_gpvD) lemma results_gpv_left_gpv [simp]: "results_gpv (\1 \\<^sub>\ \2) (left_gpv gpv) = results_gpv \1 gpv" (is "?lhs = ?rhs") proof(rule Set.set_eqI iffI)+ show "x \ ?rhs" if "x \ ?lhs" for x using that by(induction gpv'\"left_gpv gpv :: ('a, 'b + 'c, 'd + 'e) gpv" arbitrary: gpv rule: results_gpv.induct) (fastforce intro: results_gpv.intros)+ show "x \ ?lhs" if "x \ ?rhs" for x using that by(induction)(fastforce intro: results_gpv.intros)+ qed lemma results_gpv_right_gpv [simp]: "results_gpv (\1 \\<^sub>\ \2) (right_gpv gpv) = results_gpv \2 gpv" (is "?lhs = ?rhs") proof(rule Set.set_eqI iffI)+ show "x \ ?rhs" if "x \ ?lhs" for x using that by(induction gpv'\"right_gpv gpv :: ('a, 'b + 'c, 'd + 'e) gpv" arbitrary: gpv rule: results_gpv.induct) (fastforce intro: results_gpv.intros)+ show "x \ ?lhs" if "x \ ?rhs" for x using that by(induction)(fastforce intro: results_gpv.intros)+ qed lemma left_gpv_Fail [simp]: "left_gpv Fail = Fail" by(rule gpv.expand) auto lemma right_gpv_Fail [simp]: "right_gpv Fail = Fail" by(rule gpv.expand) auto lemma rsuml_lsumr_left_gpv_left_gpv:"map_gpv' id rsuml lsumr (left_gpv (left_gpv gpv)) = left_gpv gpv" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split elim!: lsumr.elims intro: exI[where x=Fail]) lemma rsuml_lsumr_left_gpv_right_gpv: "map_gpv' id rsuml lsumr (left_gpv (right_gpv gpv)) = right_gpv (left_gpv gpv)" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split elim!: lsumr.elims intro: exI[where x=Fail]) lemma rsuml_lsumr_right_gpv: "map_gpv' id rsuml lsumr (right_gpv gpv) = right_gpv (right_gpv gpv)" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split elim!: lsumr.elims intro: exI[where x=Fail]) lemma map_gpv'_map_gpv_swap: "map_gpv' f g h (map_gpv f' id gpv) = map_gpv (f \ f') id (map_gpv' id g h gpv)" by(simp add: map_gpv_conv_map_gpv' map_gpv'_comp) lemma lsumr_rsuml_left_gpv: "map_gpv' id lsumr rsuml (left_gpv gpv) = left_gpv (left_gpv gpv)" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split intro: exI[where x=Fail]) lemma lsumr_rsuml_right_gpv_left_gpv: "map_gpv' id lsumr rsuml (right_gpv (left_gpv gpv)) = left_gpv (right_gpv gpv)" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split intro: exI[where x=Fail]) lemma lsumr_rsuml_right_gpv_right_gpv: "map_gpv' id lsumr rsuml (right_gpv (right_gpv gpv)) = right_gpv gpv" by(coinduction arbitrary: gpv) (auto 4 3 simp add: spmf_rel_map generat.rel_map intro!: rel_spmf_reflI rel_generat_reflI rel_funI split!: sum.split elim!: rsuml.elims intro: exI[where x=Fail]) lemma in_set_spmf_extend_state_oracle [simp]: "x \ set_spmf (extend_state_oracle oracle s y) \ fst (snd x) = fst s \ (fst x, snd (snd x)) \ set_spmf (oracle (snd s) y)" by(auto 4 4 simp add: extend_state_oracle_def split_beta intro: rev_image_eqI prod.expand) lemma extend_state_oracle_plus_oracle: "extend_state_oracle (plus_oracle oracle1 oracle2) = plus_oracle (extend_state_oracle oracle1) (extend_state_oracle oracle2)" proof ((rule ext)+; goal_cases) case (1 s q) then show ?case by (cases s; cases q) (simp_all add: apfst_def spmf.map_comp o_def split_def) qed definition stateless_callee :: "('a \ ('b, 'out, 'in) gpv) \ ('s \ 'a \ ('b \ 's, 'out, 'in) gpv)" where "stateless_callee callee s = map_gpv (\b. (b, s)) id \ callee" lemma stateless_callee_parametric': includes lifting_syntax notes [transfer_rule] = map_gpv_parametric' shows "((A ===> rel_gpv'' B C R) ===> S ===> A ===> (rel_gpv'' (rel_prod B S) C R)) stateless_callee stateless_callee" unfolding stateless_callee_def by transfer_prover lemma id_oralce_alt_def: "id_oracle = stateless_callee (\x. Pause x Done)" by(simp add: id_oracle_def fun_eq_iff stateless_callee_def) context fixes left :: "'s1 \ 'x1 \ ('y1 \ 's1, 'call1, 'ret1) gpv" and right :: "'s2 \ 'x2 \ ('y2 \ 's2, 'call2, 'ret2) gpv" begin fun parallel_intercept :: "'s1 \ 's2 \ 'x1 + 'x2 \ (('y1 + 'y2) \ ('s1 \ 's2), 'call1 + 'call2, 'ret1 + 'ret2) gpv" where "parallel_intercept (s1, s2) (Inl a) = left_gpv (map_gpv (map_prod Inl (\s1'. (s1', s2))) id (left s1 a))" | "parallel_intercept (s1, s2) (Inr b) = right_gpv (map_gpv (map_prod Inr (Pair s1)) id (right s2 b))" end (* GPV_Expectation *) lemma expectation_gpv_\_mono: defines "expectation_gpv' \ expectation_gpv" assumes le: "\ \ \'" and WT: "\ \g gpv \" shows "expectation_gpv fail \ f gpv \ expectation_gpv' fail \' f gpv" using WT proof(induction arbitrary: gpv rule: expectation_gpv_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case step [unfolded expectation_gpv'_def]: (step expectation_gpv') show ?case unfolding expectation_gpv'_def by(subst expectation_gpv.simps) (clarsimp intro!: add_mono nn_integral_mono_AE INF_mono split: generat.split , auto intro!: bexI step add_mono nn_integral_mono_AE INF_mono split: generat.split dest: WT_gpvD[OF step.prems] intro!: step dest: responses_\_mono[OF le]) qed lemma pgen_lossless_gpv_mono: assumes *: "pgen_lossless_gpv fail \ gpv" and le: "\ \ \'" and WT: "\ \g gpv \" and fail: "fail \ 1" shows "pgen_lossless_gpv fail \' gpv" unfolding pgen_lossless_gpv_def proof(rule antisym) from WT le have "\' \g gpv \" by(rule WT_gpv_\_mono) from expectation_gpv_const_le[OF this, of fail 1] fail show "expectation_gpv fail \' (\_. 1) gpv \ 1" by(simp add: max_def split: if_split_asm) from expectation_gpv_\_mono[OF le WT, of fail "\_. 1"] * show "expectation_gpv fail \' (\_. 1) gpv \ 1" by(simp add: pgen_lossless_gpv_def) qed lemma plossless_gpv_mono: "\ plossless_gpv \ gpv; \ \ \'; \ \g gpv \ \ \ plossless_gpv \' gpv" by(erule pgen_lossless_gpv_mono; simp) lemma pfinite_gpv_mono: "\ pfinite_gpv \ gpv; \ \ \'; \ \g gpv \ \ \ pfinite_gpv \' gpv" by(erule pgen_lossless_gpv_mono; simp) lemma pgen_lossless_gpv_parametric': includes lifting_syntax shows "((=) ===> rel_\ C R ===> rel_gpv'' A C R ===> (=)) pgen_lossless_gpv pgen_lossless_gpv" unfolding pgen_lossless_gpv_def supply expectation_gpv_parametric'[transfer_rule] by transfer_prover lemma pgen_lossless_gpv_parametric: includes lifting_syntax shows "((=) ===> rel_\ C (=) ===> rel_gpv A C ===> (=)) pgen_lossless_gpv pgen_lossless_gpv" using pgen_lossless_gpv_parametric'[of C "(=)" A] by(simp add: rel_gpv_conv_rel_gpv'') lemma pgen_lossless_gpv_map_gpv_id [simp]: "pgen_lossless_gpv fail \ (map_gpv f id gpv) = pgen_lossless_gpv fail \ gpv" using pgen_lossless_gpv_parametric[of "BNF_Def.Grp UNIV id" "BNF_Def.Grp UNIV f"] unfolding gpv.rel_Grp by(auto simp add: eq_alt[symmetric] rel_\_eq rel_fun_def Grp_iff) context raw_converter_invariant begin lemma expectation_gpv_le_inline: defines "expectation_gpv2 \ expectation_gpv 0 \'" assumes callee: "\s x. \ x \ outs_\ \; I s \ \ plossless_gpv \' (callee s x)" and WT_gpv: "\ \g gpv \" and I: "I s" shows "expectation_gpv 0 \ f gpv \ expectation_gpv2 (\(x, s). f x) (inline callee gpv s)" using WT_gpv I proof(induction arbitrary: gpv s rule: expectation_gpv_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case (step expectation_gpv') { fix out c assume IO: "IO out c \ set_spmf (the_gpv gpv)" with step.prems (1) have out: "out \ outs_\ \" by(rule WT_gpv_OutD) - have "(INF r:responses_\ \ out. expectation_gpv' (c r)) = \\<^sup>+ generat. (INF r:responses_\ \ out. expectation_gpv' (c r)) \measure_spmf (the_gpv (callee s out))" + have "(INF r\responses_\ \ out. expectation_gpv' (c r)) = \\<^sup>+ generat. (INF r\responses_\ \ out. expectation_gpv' (c r)) \measure_spmf (the_gpv (callee s out))" using WT_callee[OF out, of s] callee[OF out, of s] \I s\ by(clarsimp simp add: measure_spmf.emeasure_eq_measure plossless_iff_colossless_pfinite colossless_gpv_lossless_spmfD lossless_weight_spmfD) also have "\ \ \\<^sup>+ generat. (case generat of Pure (x, s') \ \\<^sup>+ xx. (case xx of Inl (x, _) \ f x - | Inr (out', callee', rpv) \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) + | Inr (out', callee', rpv) \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) \measure_spmf (inline1 callee (c x) s') - | IO out' rpv \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')) + | IO out' rpv \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')) \measure_spmf (the_gpv (callee s out))" proof(rule nn_integral_mono_AE; simp split!: generat.split) fix x s' assume Pure: "Pure (x, s') \ set_spmf (the_gpv (callee s out))" hence "(x, s') \ results_gpv \' (callee s out)" by(rule results_gpv.Pure) with results_callee[OF out, of s] \I s\ have x: "x \ responses_\ \ out" and "I s'" by blast+ - from x have "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ expectation_gpv' (c x)" by(rule INF_lower) + from x have "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ expectation_gpv' (c x)" by(rule INF_lower) also have "\ \ expectation_gpv2 (\(x, s). f x) (inline callee (c x) s')" by(rule step.IH)(rule WT_gpv_ContD[OF step.prems(1) IO x] step.prems \I s'\|assumption)+ also have "\ = \\<^sup>+ xx. (case xx of Inl (x, _) \ f x - | Inr (out', callee', rpv) \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) + | Inr (out', callee', rpv) \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) \measure_spmf (inline1 callee (c x) s')" unfolding expectation_gpv2_def by(subst expectation_gpv.simps)(auto simp add: inline_sel split_def o_def intro!: nn_integral_cong split: generat.split sum.split) - finally show "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ \" . + finally show "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ \" . next fix out' rpv assume IO': "IO out' rpv \ set_spmf (the_gpv (callee s out))" - have "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ (INF (r, s'):(\r'\responses_\ \' out'. results_gpv \' (rpv r')). expectation_gpv' (c r))" + have "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ (INF (r, s')\(\r'\responses_\ \' out'. results_gpv \' (rpv r')). expectation_gpv' (c r))" using IO' results_callee[OF out, of s] \I s\ by(intro INF_mono)(auto intro: results_gpv.IO) - also have "\ = (INF r':responses_\ \' out'. INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r))" + also have "\ = (INF r'\responses_\ \' out'. INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r))" by(simp add: INF_UNION) - also have "\ \ (INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r'))" + also have "\ \ (INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r'))" proof(rule INF_mono, rule bexI) fix r' assume r': "r' \ responses_\ \' out'" - have "(INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r)) \ (INF (r, s'):results_gpv \' (rpv r'). expectation_gpv2 (\(x, s). f x) (inline callee (c r) s'))" + have "(INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r)) \ (INF (r, s')\results_gpv \' (rpv r'). expectation_gpv2 (\(x, s). f x) (inline callee (c r) s'))" using IO IO' step.prems out results_callee[OF out, of s] r' by(auto intro!: INF_mono rev_bexI step.IH dest: WT_gpv_ContD intro: results_gpv.IO) also have "\ \ expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')" unfolding expectation_gpv2_def using plossless_gpv_ContD[OF callee, OF out \I s\ IO' r'] WT_callee[OF out \I s\] IO' r' by(intro plossless_INF_le_expectation_gpv)(auto intro: WT_gpv_ContD) - finally show "(INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r)) \ \" . + finally show "(INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r)) \ \" . qed - finally show "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ \" . + finally show "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ \" . qed also note calculation } then show ?case unfolding expectation_gpv2_def apply(rewrite expectation_gpv.simps) apply(rewrite inline_sel) apply(simp add: o_def pmf_map_spmf_None) apply(rewrite sum.case_distrib[where h="case_generat _ _"]) apply(simp cong del: sum.case_cong_weak) apply(simp add: split_beta o_def cong del: sum.case_cong_weak) apply(rewrite inline1.simps) apply(rewrite measure_spmf_bind) apply(rewrite nn_integral_bind[where B="measure_spmf _"]) apply simp apply(simp add: space_subprob_algebra) apply(rule nn_integral_mono_AE) apply(clarsimp split!: generat.split) apply(simp add: measure_spmf_return_spmf nn_integral_return) apply(rewrite measure_spmf_bind) apply(simp add: nn_integral_bind[where B="measure_spmf _"] space_subprob_algebra) apply(subst generat.case_distrib[where h="measure_spmf"]) apply(subst generat.case_distrib[where h="\x. nn_integral x _"]) apply(simp add: measure_spmf_return_spmf nn_integral_return split_def) done qed lemma plossless_inline: assumes lossless: "plossless_gpv \ gpv" and WT: "\ \g gpv \" and callee: "\s x. \ I s; x \ outs_\ \ \ \ plossless_gpv \' (callee s x)" and I: "I s" shows "plossless_gpv \' (inline callee gpv s)" unfolding pgen_lossless_gpv_def proof(rule antisym) have WT': "\' \g inline callee gpv s \" using WT I by(rule WT_gpv_inline_invar) from expectation_gpv_const_le[OF WT', of 0 1] show "expectation_gpv 0 \' (\_. 1) (inline callee gpv s) \ 1" by(simp add: max_def) have "1 = expectation_gpv 0 \ (\_. 1) gpv" using lossless by(simp add: pgen_lossless_gpv_def) also have "\ \ expectation_gpv 0 \' (\_. 1) (inline callee gpv s)" by(rule expectation_gpv_le_inline[unfolded split_def]; rule callee I WT) finally show "1 \ \" . qed end lemma expectation_left_gpv [simp]: "expectation_gpv fail (\ \\<^sub>\ \') f (left_gpv gpv) = expectation_gpv fail \ f gpv" proof(induction arbitrary: gpv rule: parallel_fixp_induct_1_1[OF complete_lattice_partial_function_definitions complete_lattice_partial_function_definitions expectation_gpv.mono expectation_gpv.mono expectation_gpv_def expectation_gpv_def, case_names adm bottom step]) case adm show ?case by simp case bottom show ?case by simp case (step expectation_gpv' expectation_gpv'') show ?case by (auto simp add: pmf_map_spmf_None o_def case_map_generat image_comp split: generat.split intro!: nn_integral_cong_AE INF_cong step.IH) qed lemma expectation_right_gpv [simp]: "expectation_gpv fail (\ \\<^sub>\ \') f (right_gpv gpv) = expectation_gpv fail \' f gpv" proof(induction arbitrary: gpv rule: parallel_fixp_induct_1_1[OF complete_lattice_partial_function_definitions complete_lattice_partial_function_definitions expectation_gpv.mono expectation_gpv.mono expectation_gpv_def expectation_gpv_def, case_names adm bottom step]) case adm show ?case by simp case bottom show ?case by simp case (step expectation_gpv' expectation_gpv'') show ?case by (auto simp add: pmf_map_spmf_None o_def case_map_generat image_comp split: generat.split intro!: nn_integral_cong_AE INF_cong step.IH) qed lemma pgen_lossless_left_gpv [simp]: "pgen_lossless_gpv fail (\ \\<^sub>\ \') (left_gpv gpv) = pgen_lossless_gpv fail \ gpv" by(simp add: pgen_lossless_gpv_def) lemma pgen_lossless_right_gpv [simp]: "pgen_lossless_gpv fail (\ \\<^sub>\ \') (right_gpv gpv) = pgen_lossless_gpv fail \' gpv" by(simp add: pgen_lossless_gpv_def) lemma (in raw_converter_invariant) expectation_gpv_le_inline_invariant: defines "expectation_gpv2 \ expectation_gpv 0 \'" assumes callee: "\s x. \ x \ outs_\ \; I s \ \ plossless_gpv \' (callee s x)" and WT_gpv: "\ \g gpv \" and I: "I s" shows "expectation_gpv 0 \ f gpv \ expectation_gpv2 (\(x, s). f x) (inline callee gpv s)" using WT_gpv I proof(induction arbitrary: gpv s rule: expectation_gpv_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case (step expectation_gpv') { fix out c assume IO: "IO out c \ set_spmf (the_gpv gpv)" with step.prems(1) have out: "out \ outs_\ \" by(rule WT_gpv_OutD) - have "(INF r:responses_\ \ out. expectation_gpv' (c r)) = \\<^sup>+ generat. (INF r:responses_\ \ out. expectation_gpv' (c r)) \measure_spmf (the_gpv (callee s out))" + have "(INF r\responses_\ \ out. expectation_gpv' (c r)) = \\<^sup>+ generat. (INF r\responses_\ \ out. expectation_gpv' (c r)) \measure_spmf (the_gpv (callee s out))" using WT_callee[OF out, of s] callee[OF out, of s] step.prems(2) by(clarsimp simp add: measure_spmf.emeasure_eq_measure plossless_iff_colossless_pfinite colossless_gpv_lossless_spmfD lossless_weight_spmfD) also have "\ \ \\<^sup>+ generat. (case generat of Pure (x, s') \ \\<^sup>+ xx. (case xx of Inl (x, _) \ f x - | Inr (out', callee', rpv) \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) + | Inr (out', callee', rpv) \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) \measure_spmf (inline1 callee (c x) s') - | IO out' rpv \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')) + | IO out' rpv \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')) \measure_spmf (the_gpv (callee s out))" proof(rule nn_integral_mono_AE; simp split!: generat.split) fix x s' assume Pure: "Pure (x, s') \ set_spmf (the_gpv (callee s out))" hence "(x, s') \ results_gpv \' (callee s out)" by(rule results_gpv.Pure) with results_callee[OF out step.prems(2)] have x: "x \ responses_\ \ out" and s': "I s'" by blast+ - from this(1) have "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ expectation_gpv' (c x)" by(rule INF_lower) + from this(1) have "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ expectation_gpv' (c x)" by(rule INF_lower) also have "\ \ expectation_gpv2 (\(x, s). f x) (inline callee (c x) s')" by(rule step.IH)(rule WT_gpv_ContD[OF step.prems(1) IO x] step.prems s'|assumption)+ also have "\ = \\<^sup>+ xx. (case xx of Inl (x, _) \ f x - | Inr (out', callee', rpv) \ INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) + | Inr (out', callee', rpv) \ INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r, s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (rpv r) s')) (callee' r')) \measure_spmf (inline1 callee (c x) s')" unfolding expectation_gpv2_def by(subst expectation_gpv.simps)(auto simp add: inline_sel split_def o_def intro!: nn_integral_cong split: generat.split sum.split) - finally show "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ \" . + finally show "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ \" . next fix out' rpv assume IO': "IO out' rpv \ set_spmf (the_gpv (callee s out))" - have "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ (INF (r, s'):(\r'\responses_\ \' out'. results_gpv \' (rpv r')). expectation_gpv' (c r))" + have "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ (INF (r, s')\(\r'\responses_\ \' out'. results_gpv \' (rpv r')). expectation_gpv' (c r))" using IO' results_callee[OF out step.prems(2)] by(intro INF_mono)(auto intro: results_gpv.IO) - also have "\ = (INF r':responses_\ \' out'. INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r))" + also have "\ = (INF r'\responses_\ \' out'. INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r))" by(simp add: INF_UNION) - also have "\ \ (INF r':responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r'))" + also have "\ \ (INF r'\responses_\ \' out'. expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r'))" proof(rule INF_mono, rule bexI) fix r' assume r': "r' \ responses_\ \' out'" - have "(INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r)) \ (INF (r, s'):results_gpv \' (rpv r'). expectation_gpv2 (\(x, s). f x) (inline callee (c r) s'))" + have "(INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r)) \ (INF (r, s')\results_gpv \' (rpv r'). expectation_gpv2 (\(x, s). f x) (inline callee (c r) s'))" using IO IO' step.prems out results_callee[OF out, of s] r' by(auto intro!: INF_mono rev_bexI step.IH dest: WT_gpv_ContD intro: results_gpv.IO) also have "\ \ expectation_gpv 0 \' (\(r', s'). expectation_gpv 0 \' (\(x, s). f x) (inline callee (c r') s')) (rpv r')" unfolding expectation_gpv2_def using plossless_gpv_ContD[OF callee, OF out step.prems(2) IO' r'] WT_callee[OF out step.prems(2)] IO' r' by(intro plossless_INF_le_expectation_gpv)(auto intro: WT_gpv_ContD) - finally show "(INF (r, s'):results_gpv \' (rpv r'). expectation_gpv' (c r)) \ \" . + finally show "(INF (r, s')\results_gpv \' (rpv r'). expectation_gpv' (c r)) \ \" . qed - finally show "(INF r:responses_\ \ out. expectation_gpv' (c r)) \ \" . + finally show "(INF r\responses_\ \ out. expectation_gpv' (c r)) \ \" . qed also note calculation } then show ?case unfolding expectation_gpv2_def apply(rewrite expectation_gpv.simps) apply(rewrite inline_sel) apply(simp add: o_def pmf_map_spmf_None) apply(rewrite sum.case_distrib[where h="case_generat _ _"]) apply(simp cong del: sum.case_cong_weak) apply(simp add: split_beta o_def cong del: sum.case_cong_weak) apply(rewrite inline1.simps) apply(rewrite measure_spmf_bind) apply(rewrite nn_integral_bind[where B="measure_spmf _"]) apply simp apply(simp add: space_subprob_algebra) apply(rule nn_integral_mono_AE) apply(clarsimp split!: generat.split) apply(simp add: measure_spmf_return_spmf nn_integral_return) apply(rewrite measure_spmf_bind) apply(simp add: nn_integral_bind[where B="measure_spmf _"] space_subprob_algebra) apply(subst generat.case_distrib[where h="measure_spmf"]) apply(subst generat.case_distrib[where h="\x. nn_integral x _"]) apply(simp add: measure_spmf_return_spmf nn_integral_return split_def) done qed lemma (in raw_converter_invariant) plossless_inline_invariant: assumes lossless: "plossless_gpv \ gpv" and WT: "\ \g gpv \" and callee: "\s x. \ x \ outs_\ \; I s \ \ plossless_gpv \' (callee s x)" and I: "I s" shows "plossless_gpv \' (inline callee gpv s)" unfolding pgen_lossless_gpv_def proof(rule antisym) have WT': "\' \g inline callee gpv s \" using WT I by(rule WT_gpv_inline_invar) from expectation_gpv_const_le[OF WT', of 0 1] show "expectation_gpv 0 \' (\_. 1) (inline callee gpv s) \ 1" by(simp add: max_def) have "1 = expectation_gpv 0 \ (\_. 1) gpv" using lossless by(simp add: pgen_lossless_gpv_def) also have "\ \ expectation_gpv 0 \' (\_. 1) (inline callee gpv s)" by(rule expectation_gpv_le_inline[unfolded split_def]; rule callee WT WT_callee I) finally show "1 \ \" . qed context callee_invariant_on begin lemma raw_converter_invariant: "raw_converter_invariant \ \' (\s x. lift_spmf (callee s x)) I" by(unfold_locales)(auto dest: callee_invariant WT_callee WT_calleeD) lemma (in callee_invariant_on) plossless_exec_gpv: assumes lossless: "plossless_gpv \ gpv" and WT: "\ \g gpv \" and callee: "\s x. \ x \ outs_\ \; I s \ \ lossless_spmf (callee s x)" and I: "I s" shows "lossless_spmf (exec_gpv callee gpv s)" proof - interpret raw_converter_invariant \ \' "\s x. lift_spmf (callee s x)" I for \' by(rule raw_converter_invariant) have "plossless_gpv \_full (inline (\s x. lift_spmf (callee s x)) gpv s)" using lossless WT by(rule plossless_inline)(simp_all add: callee I) from this[THEN plossless_gpv_lossless_spmfD] show ?thesis unfolding exec_gpv_conv_inline1 by(simp add: inline_sel) qed end definition extend_state_oracle2 :: "('call, 'ret, 's) callee \ ('call, 'ret, 's \ 's') callee" ("_\" [1000] 1000) where "extend_state_oracle2 callee = (\(s, s') x. map_spmf (\(y, s). (y, (s, s'))) (callee s x))" lemma extend_state_oracle2_simps [simp]: "extend_state_oracle2 callee (s, s') x = map_spmf (\(y, s). (y, (s, s'))) (callee s x)" by(simp add: extend_state_oracle2_def) lemma extend_state_oracle2_parametric [transfer_rule]: includes lifting_syntax shows "((S ===> C ===> rel_spmf (rel_prod R S)) ===> rel_prod S S' ===> C ===> rel_spmf (rel_prod R (rel_prod S S'))) extend_state_oracle2 extend_state_oracle2" unfolding extend_state_oracle2_def[abs_def] by transfer_prover lemma callee_invariant_extend_state_oracle2_const [simp]: "callee_invariant oracle\ (\(s, s'). I s')" by unfold_locales auto lemma callee_invariant_extend_state_oracle2_const': "callee_invariant oracle\ (\s. I (snd s))" by unfold_locales auto lemma extend_state_oracle2_plus_oracle: "extend_state_oracle2 (plus_oracle oracle1 oracle2) = plus_oracle (extend_state_oracle2 oracle1) (extend_state_oracle2 oracle2)" proof((rule ext)+; goal_cases) case (1 s q) then show ?case by (cases s; cases q) (simp_all add: apfst_def spmf.map_comp o_def split_def) qed lemma parallel_oracle_conv_plus_oracle: "parallel_oracle oracle1 oracle2 = plus_oracle (oracle1\) (\oracle2)" proof((rule ext)+; goal_cases) case (1 s q) then show ?case by (cases s; cases q) (auto simp add: spmf.map_comp apfst_def o_def split_def map_prod_def) qed lemma map_sum_parallel_oracle: includes lifting_syntax shows "(id ---> map_sum f g ---> map_spmf (map_prod (map_sum h k) id)) (parallel_oracle oracle1 oracle2) = parallel_oracle ((id ---> f ---> map_spmf (map_prod h id)) oracle1) ((id ---> g ---> map_spmf (map_prod k id)) oracle2)" proof((rule ext)+; goal_cases) case (1 s q) then show ?case by (cases s; cases q) (simp_all add: spmf.map_comp o_def apfst_def prod.map_comp) qed lemma map_sum_plus_oracle: includes lifting_syntax shows "(id ---> map_sum f g ---> map_spmf (map_prod (map_sum h k) id)) (plus_oracle oracle1 oracle2) = plus_oracle ((id ---> f ---> map_spmf (map_prod h id)) oracle1) ((id ---> g ---> map_spmf (map_prod k id)) oracle2)" proof((rule ext)+; goal_cases) case (1 s q) then show ?case by (cases q) (simp_all add: spmf.map_comp o_def apfst_def prod.map_comp) qed lemma map_rsuml_plus_oracle: includes lifting_syntax shows "(id ---> rsuml ---> (map_spmf (map_prod lsumr id))) (oracle1 \\<^sub>O (oracle2 \\<^sub>O oracle3)) = ((oracle1 \\<^sub>O oracle2) \\<^sub>O oracle3)" proof((rule ext)+; goal_cases) case (1 s q) then show ?case proof(cases q) case (Inl ql) then show ?thesis by(cases ql)(simp_all add: spmf.map_comp o_def apfst_def prod.map_comp) qed (simp add: spmf.map_comp o_def apfst_def prod.map_comp id_def) qed lemma map_lsumr_plus_oracle: includes lifting_syntax shows "(id ---> lsumr ---> (map_spmf (map_prod rsuml id))) ((oracle1 \\<^sub>O oracle2) \\<^sub>O oracle3) = (oracle1 \\<^sub>O (oracle2 \\<^sub>O oracle3))" proof((rule ext)+; goal_cases) case (1 s q) then show ?case proof(cases q) case (Inr qr) then show ?thesis by(cases qr)(simp_all add: spmf.map_comp o_def apfst_def prod.map_comp) qed (simp add: spmf.map_comp o_def apfst_def prod.map_comp id_def) qed context includes lifting_syntax begin definition lift_state_oracle :: "(('s \ 'a \ (('b \ 't) \ 's) spmf) \ ('s' \ 'a \ (('b \ 't) \ 's') spmf)) \ ('t \ 's \ 'a \ ('b \ 't \ 's) spmf) \ ('t \ 's' \ 'a \ ('b \ 't \ 's') spmf)" where "lift_state_oracle F oracle = (\(t, s') a. map_spmf rprodl (F ((Pair t ---> id ---> map_spmf lprodr) oracle) s' a))" lemma lift_state_oracle_simps [simp]: "lift_state_oracle F oracle (t, s') a = map_spmf rprodl (F ((Pair t ---> id ---> map_spmf lprodr) oracle) s' a)" by(simp add: lift_state_oracle_def) lemma lift_state_oracle_parametric [transfer_rule]: includes lifting_syntax shows "(((S ===> A ===> rel_spmf (rel_prod (rel_prod B T) S)) ===> S' ===> A ===> rel_spmf (rel_prod (rel_prod B T) S')) ===> (rel_prod T S ===> A ===> rel_spmf (rel_prod B (rel_prod T S))) ===> rel_prod T S' ===> A ===> rel_spmf (rel_prod B (rel_prod T S'))) lift_state_oracle lift_state_oracle" unfolding lift_state_oracle_def map_fun_def o_def by transfer_prover lemma lift_state_oracle_extend_state_oracle: includes lifting_syntax assumes "\B. Transfer.Rel (((=) ===> (=) ===> rel_spmf (rel_prod B (=))) ===> (=) ===> (=) ===> rel_spmf (rel_prod B (=))) G F" (* TODO: implement simproc to discharge parametricity assumptions like this one *) shows "lift_state_oracle F (extend_state_oracle oracle) = extend_state_oracle (G oracle)" unfolding lift_state_oracle_def extend_state_oracle_def apply(clarsimp simp add: fun_eq_iff map_fun_def o_def spmf.map_comp split_def rprodl_def) subgoal for t s a apply(rule sym) apply(fold spmf_rel_eq) apply(simp add: spmf_rel_map) apply(rule rel_spmf_mono) apply(rule assms[unfolded Rel_def, where B="\x (y, z). x = y \ z = t", THEN rel_funD, THEN rel_funD, THEN rel_funD]) apply(auto simp add: rel_fun_def spmf_rel_map intro!: rel_spmf_reflI) done done lemma lift_state_oracle_compose: "lift_state_oracle F (lift_state_oracle G oracle) = lift_state_oracle (F \ G) oracle" by(simp add: lift_state_oracle_def map_fun_def o_def split_def spmf.map_comp) lemma lift_state_oracle_id [simp]: "lift_state_oracle id = id" by(simp add: fun_eq_iff spmf.map_comp o_def) lemma rprodl_extend_state_oracle: includes lifting_syntax shows "(rprodl ---> id ---> map_spmf (map_prod id lprodr)) (extend_state_oracle (extend_state_oracle oracle)) = extend_state_oracle oracle" by(simp add: fun_eq_iff spmf.map_comp o_def split_def) end lemma interaction_bound_map_gpv': assumes "surj h" shows "interaction_bound consider (map_gpv' f g h gpv) = interaction_bound (consider \ g) gpv" proof(induction arbitrary: gpv rule: parallel_fixp_induct_1_1[OF lattice_partial_function_definition lattice_partial_function_definition interaction_bound.mono interaction_bound.mono interaction_bound_def interaction_bound_def, case_names adm bottom step]) case (step interaction_bound' interaction_bound'' gpv) have *: "IO out c \ set_spmf (the_gpv gpv) \ x \ UNIV \ interaction_bound'' (c x) \ (\x. interaction_bound'' (c (h x)))" for out c x using assms[THEN surjD, of x] by (clarsimp intro!: SUP_upper) show ?case by (auto simp add: * step.IH image_comp split: generat.split intro!: SUP_cong [OF refl] antisym SUP_upper SUP_least) qed simp_all lemma interaction_any_bounded_by_map_gpv': assumes "interaction_any_bounded_by gpv n" and "surj h" shows "interaction_any_bounded_by (map_gpv' f g h gpv) n" using assms by(simp add: interaction_bounded_by.simps interaction_bound_map_gpv' o_def) lemma results'_gpv_map_gpv': assumes "surj h" shows "results'_gpv (map_gpv' f g h gpv) = f ` results'_gpv gpv" (is "?lhs = ?rhs") proof - have *:"IO z c \ set_spmf (the_gpv gpv) \ x \ results'_gpv (c input) \ f x \ results'_gpv (map_gpv' f g h (c input)) \ f x \ results'_gpv (map_gpv' f g h gpv)" for x z gpv c input using surjD[OF assms, of input] by(fastforce intro: results'_gpvI elim!: generat.set_cases intro: rev_image_eqI simp add: map_fun_def o_def) show ?thesis proof(intro Set.set_eqI iffI; (elim imageE; hypsubst)?) show "x \ ?rhs" if "x \ ?lhs" for x using that by(induction gpv'\"map_gpv' f g h gpv" arbitrary: gpv)(fastforce elim!: generat.set_cases intro: results'_gpvI)+ show "f x \ ?lhs" if "x \ results'_gpv gpv" for x using that by induction (fastforce intro: results'_gpvI elim!: generat.set_cases intro: rev_image_eqI simp add: map_fun_def o_def , clarsimp simp add: * elim!: generat.set_cases) qed qed context fixes B :: "'b \ 'c set" and x :: 'a begin primcorec mk_lossless_gpv :: "('a, 'b, 'c) gpv \ ('a, 'b, 'c) gpv" where "the_gpv (mk_lossless_gpv gpv) = map_spmf (\generat. case generat of Pure x \ Pure x | IO out c \ IO out (\input. if input \ B out then mk_lossless_gpv (c input) else Done x)) (the_gpv gpv)" end lemma WT_gpv_outs_gpvI: assumes "outs_gpv \ gpv \ outs_\ \" shows "\ \g gpv \" using assms by(coinduction arbitrary: gpv)(auto intro: outs_gpv.intros) lemma WT_gpv_iff_outs_gpv: "\ \g gpv \ \ outs_gpv \ gpv \ outs_\ \" by(blast intro: WT_gpv_outs_gpvI dest: WT_gpv_outs_gpv) lemma WT_gpv_mk_lossless_gpv: assumes "\ \g gpv \" and outs: "outs_\ \' = outs_\ \" shows "\' \g mk_lossless_gpv (responses_\ \) x gpv \" using assms(1) by(coinduction arbitrary: gpv)(auto 4 3 split: generat.split_asm simp add: outs dest: WT_gpvD) lemma expectation_gpv_mk_lossless_gpv: fixes \ y defines "rhs \ expectation_gpv 0 \ (\_. y)" assumes WT: "\' \g gpv \" and outs: "outs_\ \ = outs_\ \'" shows "expectation_gpv 0 \' (\_. y) gpv \ rhs (mk_lossless_gpv (responses_\ \') x gpv)" using WT proof(induction arbitrary: gpv rule: expectation_gpv_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case step [unfolded rhs_def]: (step expectation_gpv') show ?case using step.prems outs unfolding rhs_def apply(subst expectation_gpv.simps) apply(clarsimp intro!: nn_integral_mono_AE INF_mono split!: generat.split if_split) subgoal by(frule (1) WT_gpv_OutD)(auto simp add: in_outs_\_iff_responses_\ intro!: bexI step.IH[unfolded rhs_def] dest: WT_gpv_ContD) apply(frule (1) WT_gpv_OutD; clarsimp simp add: in_outs_\_iff_responses_\ ex_in_conv[symmetric]) subgoal for out c input input' using step.hyps[of "c input'"] expectation_gpv_const_le[of \' "c input'" 0 y] by- (drule (2) WT_gpv_ContD, fastforce intro: rev_bexI simp add: max_def) done qed lemma plossless_gpv_mk_lossless_gpv: assumes "plossless_gpv \ gpv" and "\ \g gpv \" and "outs_\ \ = outs_\ \'" shows "plossless_gpv \' (mk_lossless_gpv (responses_\ \) x gpv)" using assms expectation_gpv_mk_lossless_gpv[OF assms(2), of \' 1 x] unfolding pgen_lossless_gpv_def by -(rule antisym[OF expectation_gpv_const_le[THEN order_trans]]; simp add: WT_gpv_mk_lossless_gpv) lemma (in callee_invariant_on) exec_gpv_mk_lossless_gpv: assumes "\ \g gpv \" and "I s" shows "exec_gpv callee (mk_lossless_gpv (responses_\ \) x gpv) s = exec_gpv callee gpv s" using assms proof(induction arbitrary: gpv s rule: exec_gpv_fixp_induct) case adm show ?case by simp case bottom show ?case by simp case (step exec_gpv') show ?case using step.prems WT_gpv_OutD[OF step.prems(1)] by(clarsimp simp add: bind_map_spmf intro!: bind_spmf_cong[OF refl] split!: generat.split if_split) (force intro!: step.IH dest: WT_callee[THEN WT_calleeD] WT_gpv_OutD callee_invariant WT_gpv_ContD)+ qed lemma in_results_gpv_restrict_gpvD: assumes "x \ results_gpv \ (restrict_gpv \' gpv)" shows "x \ results_gpv \ gpv" using assms apply(induction gpv'\"restrict_gpv \' gpv" arbitrary: gpv) apply(clarsimp split: option.split_asm simp add: in_set_spmf[symmetric]) subgoal for \ y by(cases y)(auto intro: results_gpv.intros split: if_split_asm) apply(clarsimp split: option.split_asm simp add: in_set_spmf[symmetric]) subgoal for \ y by(cases y)(auto intro: results_gpv.intros split: if_split_asm) done lemma results_gpv_restrict_gpv: "results_gpv \ (restrict_gpv \' gpv) \ results_gpv \ gpv" by(blast intro: in_results_gpv_restrict_gpvD) lemma in_results'_gpv_restrict_gpvD: "x \ results'_gpv (restrict_gpv \' gpv) \ x \ results'_gpv gpv" by(rule in_results_gpv_restrict_gpvD[where \ = "\_full", unfolded results_gpv_\_full]) lemma expectation_gpv_map_gpv' [simp]: "expectation_gpv fail \ f (map_gpv' g h k gpv) = expectation_gpv fail (map_\ h k \) (f \ g) gpv" proof(induction arbitrary: gpv rule: parallel_fixp_induct_1_1[OF complete_lattice_partial_function_definitions complete_lattice_partial_function_definitions expectation_gpv.mono expectation_gpv.mono expectation_gpv_def expectation_gpv_def, case_names adm bottom step]) case adm show ?case by simp case bottom show ?case by simp case (step exp1 exp2) have "pmf (the_gpv (map_gpv' g h k gpv)) None = pmf (the_gpv gpv) None" by(simp add: pmf_map_spmf_None) then show ?case by simp (auto simp add: nn_integral_measure_spmf step.IH image_comp split: generat.split intro!: nn_integral_cong) qed lemma plossless_gpv_map_gpv' [simp]: "pgen_lossless_gpv b \ (map_gpv' f g h gpv) \ pgen_lossless_gpv b (map_\ g h \) gpv" unfolding pgen_lossless_gpv_def by(simp add: o_def) end \ No newline at end of file diff --git a/thys/Euler_Partition/Euler_Partition.thy b/thys/Euler_Partition/Euler_Partition.thy --- a/thys/Euler_Partition/Euler_Partition.thy +++ b/thys/Euler_Partition/Euler_Partition.thy @@ -1,492 +1,485 @@ (* Author: Lukas Bulwahn Dedicated to Sandra H. for a wonderful relaxing summer *) section \Euler's Partition Theorem\ theory Euler_Partition imports Main Card_Number_Partitions.Number_Partition begin subsection \Preliminaries\ subsubsection \Additions to Divides Theory\ lemma power_div_nat: assumes "c \ b" assumes "a > 0" shows "(a :: nat) ^ b div a ^ c = a ^ (b - c)" by (metis assms nonzero_mult_div_cancel_right le_add_diff_inverse2 less_not_refl2 power_add power_not_zero) subsubsection \Additions to Groups-Big Theory\ lemma sum_div: assumes "finite A" assumes "\a. a \ A \ (b::'b::euclidean_semiring) dvd f a" shows "(\a\A. f a) div b = (\a\A. (f a) div b)" using assms proof (induct) case insert from this show ?case by auto (subst div_add; auto intro!: dvd_sum) qed (auto) lemma sum_mod: assumes "finite A" assumes "\a. a \ A \ f a mod b = (0::'b::unique_euclidean_semiring)" shows "(\a\A. f a) mod b = 0" using assms by induct (auto simp add: mod_add_eq [symmetric]) subsubsection \Additions to Finite-Set Theory\ lemma finite_exponents: "finite {i. 2 ^ i \ (n::nat)}" proof - have "{i::nat. 2 ^ i \ n} \ {0..n}" using dual_order.trans by fastforce from finite_subset[OF this] show ?thesis by simp qed subsection \Binary Encoding of Natural Numbers\ definition bitset :: "nat \ nat set" where "bitset n = {i. odd (n div (2 ^ i))}" lemma in_bitset_bound: "b \ bitset n \ 2 ^ b \ n" unfolding bitset_def using not_less by fastforce lemma in_bitset_bound_weak: "b \ bitset n \ b \ n" by (meson order.trans in_bitset_bound self_le_ge2_pow[OF order_refl]) lemma finite_bitset: "finite (bitset n)" proof - have "bitset n \ {..n}" by (auto dest: in_bitset_bound_weak) from this show ?thesis using finite_subset by auto qed lemma bitset_0: "bitset 0 = {}" unfolding bitset_def by auto -lemma binary_induct [case_names zero even odd]: - assumes "P (0 :: nat)" - assumes "\n. P n \ P (2 * n)" - assumes "\n. P n \ P (2 * n + 1)" - shows "\n. P n" -using assms parity_induct by auto - lemma bitset_2n: "bitset (2 * n) = Suc ` (bitset n)" proof (rule set_eqI) fix x show "(x \ bitset (2 * n)) = (x \ Suc ` bitset n)" unfolding bitset_def by (cases x) auto qed lemma bitset_Suc: assumes "even n" shows "bitset (n + 1) = insert 0 (bitset n)" proof (rule set_eqI) fix x from assms show "(x \ bitset (n + 1)) = (x \ insert 0 (bitset n))" unfolding bitset_def by (cases x) (auto simp add: Divides.div_mult2_eq) qed lemma bitset_2n1: "bitset (2 * n + 1) = insert 0 (Suc ` (bitset n))" by (subst bitset_Suc) (auto simp add: bitset_2n) lemma sum_bitset: "(\i\bitset n. 2 ^ i) = n" -proof (induct rule: binary_induct) +proof (induct rule: nat_parity_induct) case zero show ?case by (auto simp add: bitset_0) next case (even n) from this show ?case by (simp add: bitset_2n sum.reindex sum_distrib_left[symmetric]) next case (odd n) have "(\i\bitset (2 * n + 1). 2 ^ i) = (\i\insert 0 (Suc ` bitset n). 2 ^ i)" by (simp only: bitset_2n1) also have "... = 2 ^ 0 + (\i\Suc ` bitset n. 2 ^ i)" by (subst sum.insert) (auto simp add: finite_bitset) also have "... = 2 * n + 1" using odd by (simp add: sum.reindex sum_distrib_left[symmetric]) - finally show ?case . + finally show ?case by simp qed lemma binarysum_div: assumes "finite B" shows "(\i\B. (2::nat) ^ i) div 2 ^ j = (\i\B. if i < j then 0 else 2 ^ (i - j))" (is "_ = (\i\_. ?f i)") proof - have split_B: "B = {i\B. i < j} \ {i\B. j \ i}" by auto have bound: "(\i | i \ B \ i < j. (2::nat) ^ i) < 2 ^ j" proof (rule order.strict_trans1) show "(\i | i \ B \ i < j. (2::nat) ^ i) \ (\ii | i \ B \ i < j. (2::nat) ^ i) div (2 ^ j) = 0" by (elim div_less) from assms have mod0: "(\i | i \ B \ j \ i. (2::nat) ^ i) mod 2 ^ j = 0" by (auto intro!: sum_mod simp add: le_imp_power_dvd) from assms have "(\i\B. (2::nat) ^ i) div (2 ^ j) = ((\i | i \ B \ i < j. 2 ^ i) + (\i | i \ B \ j \ i. 2 ^ i)) div 2 ^ j" by (subst sum.union_disjoint[symmetric]) (auto simp add: split_B[symmetric]) also have "... = (\i | i \ B \ j \ i. 2 ^ i) div 2 ^ j" by (simp add: div_add1_eq zero mod0) also have "... = (\i | i \ B \ j \ i. 2 ^ i div 2 ^ j)" using assms by (subst sum_div) (auto simp add: sum_div le_imp_power_dvd) also have "... = (\i | i \ B \ j \ i. 2 ^ (i - j))" by (rule sum.cong[OF refl]) (auto simp add: power_div_nat) also have "... = (\i\B. ?f i)" using assms by (subst split_B; subst sum.union_disjoint) auto finally show ?thesis . qed lemma odd_iff: assumes "finite B" shows "odd (\i\B. if i < x then (0::nat) else 2 ^ (i - x)) = (x \ B)" (is "odd (\i\_. ?s i) = _") proof - from assms have even: "even (\i\B - {x}. ?s i)" by (subst dvd_sum) auto show ?thesis proof assume "odd (\i\B. ?s i)" from this even show "x \ B" by (cases "x \ B") auto next assume "x \ B" from assms this have "(\i\B. ?s i) = 1 + (\i\B-{x}. ?s i)" by (auto simp add: sum.remove) from assms this even show "odd (\i\B. ?s i)" by auto qed qed lemma bitset_sum: assumes "finite B" shows "bitset (\i\B. 2 ^ i) = B" using assms unfolding bitset_def by (simp add: binarysum_div odd_iff) subsection \Decomposition of a Number into a Power of Two and an Odd Number\ function (sequential) index :: "nat \ nat" where "index 0 = 0" | "index n = (if odd n then 0 else Suc (index (n div 2)))" by (pat_completeness) auto termination proof show "wf {(x::nat, y). x < y}" by (simp add: wf) next fix n show "(Suc n div 2, Suc n) \ {(x, y). x < y}" by simp qed function (sequential) oddpart :: "nat \ nat" where "oddpart 0 = 0" | "oddpart n = (if odd n then n else oddpart (n div 2))" by pat_completeness auto termination proof show "wf {(x::nat, y). x < y}" by (simp add: wf) next fix n show "(Suc n div 2, Suc n) \ {(x, y). x < y}" by simp qed lemma odd_oddpart: "odd (oddpart n) \ n \ 0" by (induct n rule: index.induct) auto lemma index_oddpart_decomposition: "n = 2 ^ (index n) * oddpart n" proof (induct n rule: index.induct) case (2 n) from this show "Suc n = 2 ^ index (Suc n) * oddpart (Suc n)" by (simp add: mult.assoc) qed (simp) lemma oddpart_leq: "oddpart n \ n" by (induct n rule: index.induct) (simp, metis div_le_dividend le_Suc_eq le_trans oddpart.simps(2)) lemma index_oddpart_unique: assumes "odd (m :: nat)" "odd m'" shows "(2 ^ i * m = 2 ^ i' * m') \ (i = i' \ m = m')" proof (induct i arbitrary: i') case 0 from assms show ?case by auto next case (Suc _ i') from assms this show ?case by (cases i') auto qed lemma index_oddpart: assumes "odd m" shows "index (2 ^ i * m) = i" "oddpart (2 ^ i * m) = m" using index_oddpart_unique[where i=i and m=m and m'="oddpart (2 ^ i * m)" and i'="index (2 ^ i * m)"] assms odd_oddpart index_oddpart_decomposition by force+ subsection \Partitions With Only Distinct and Only Odd Parts\ definition odd_of_distinct :: "(nat \ nat) \ nat \ nat" where "odd_of_distinct p = (\i. if odd i then (\j | p (2 ^ j * i) = 1. 2 ^ j) else 0)" definition distinct_of_odd :: "(nat \ nat) \ nat \ nat" where "distinct_of_odd p = (\i. if index i \ bitset (p (oddpart i)) then 1 else 0)" lemma odd: "odd_of_distinct p i \ 0 \ odd i" unfolding odd_of_distinct_def by auto lemma distinct_distinct_of_odd: "distinct_of_odd p i \ 1" unfolding distinct_of_odd_def by auto lemma odd_of_distinct: assumes "odd_of_distinct p i \ 0" assumes "\i. p i \ 0 \ i \ n" shows "1 \ i \ i \ n" proof from assms(1) odd have "odd i" by simp then show "1 \ i" by (auto elim: oddE) next from assms(1) obtain j where "p (2 ^ j * i) > 0" by (auto simp add: odd_of_distinct_def split: if_splits) fastforce with assms(2) have "i \ 2 ^ j * i" "2 ^ j * i \ n" by simp_all then show "i \ n" by (rule order_trans) qed lemma distinct_of_odd: assumes "\i. p i * i \ n" "\i. p i \ 0 \ odd i" assumes "distinct_of_odd p i \ 0" shows "1 \ i \ i \ n" proof from assms(3) have index: "index i \ bitset (p (oddpart i))" unfolding distinct_of_odd_def by (auto split: if_split_asm) have "i \ 0" proof assume zero: "i = 0" from assms(2) have "p 0 = 0" by auto from index zero this show "False" by (auto simp add: bitset_0) qed from this show "1 \ i" by auto from assms(1) have leq_n: "p (oddpart i) * oddpart i \ n" by auto from index have "2 ^ index i \ p (oddpart i)" by (rule in_bitset_bound) from this leq_n show "i \ n" by (subst index_oddpart_decomposition[of i]) (meson dual_order.trans eq_imp_le mult_le_mono) qed lemma odd_distinct: assumes "\i. p i \ 0 \ odd i" shows "odd_of_distinct (distinct_of_odd p) = p" using assms unfolding odd_of_distinct_def distinct_of_odd_def by (auto simp add: fun_eq_iff index_oddpart sum_bitset) lemma distinct_odd: assumes "\i. p i \ 0 \ 1 \ i \ i \ n" "\i. p i \ 1" shows "distinct_of_odd (odd_of_distinct p) = p" proof - from assms have "{i. p i = 1} \ {..n}" by auto from this have finite: "finite {i. p i = 1}" by (simp add: finite_subset) have "\x j. x > 0 \ p (2 ^ j * oddpart x) = 1 \ index (2 ^ j * oddpart x) \ index ` {i. p i = 1 \ oddpart x = oddpart i}" by (rule imageI) (auto intro: imageI simp add: index_oddpart odd_oddpart) from this have eq: "\x. x > 0 \ {j. p (2 ^ j * oddpart x) = 1} = index ` {i. p i = 1 \ oddpart x = oddpart i}" by (auto simp add: index_oddpart odd_oddpart index_oddpart_decomposition[symmetric]) from finite have all_finite: "\x. x > 0 \ finite {j. p (2 ^ j * oddpart x) = 1}" unfolding eq by auto show ?thesis proof fix x from assms(1) have p0: "p 0 = 0" by auto show "distinct_of_odd (odd_of_distinct p) x = p x" proof (cases "x > 0") case False from this p0 show ?thesis unfolding odd_of_distinct_def distinct_of_odd_def by (auto simp add: odd_oddpart bitset_0) next case True from p0 assms(2)[of x] all_finite[OF True] show ?thesis unfolding odd_of_distinct_def distinct_of_odd_def by (auto simp add: odd_oddpart bitset_0 bitset_sum index_oddpart_decomposition[symmetric]) qed qed qed lemma sum_distinct_of_odd: assumes "\i. p i \ 0 \ 1 \ i \ i \ n" assumes "\i. p i * i \ n" assumes "\i. p i \ 0 \ odd i" shows "(\i\n. distinct_of_odd p i * i) = (\i\n. p i * i)" proof - { fix m assume odd: "odd (m :: nat)" have finite: "finite {k. 2 ^ k * m \ n \ k \ bitset (p m)}" by (simp add: finite_bitset) have "(\i | \k. i = 2 ^ k * m \ i \ n. distinct_of_odd p i * i) = (\i | \k. i = 2 ^ k * m \ i \ n. if index i \ bitset (p (oddpart i)) then i else 0)" unfolding distinct_of_odd_def by (auto intro: sum.cong) also have "... = (\i | \k. i = 2 ^ k * m \ k \ bitset (p m) \ i \ n. i)" using odd by (intro sum.mono_neutral_cong_right) (auto simp add: index_oddpart) also have "... = (\k | 2 ^ k * m \ n \ k \ bitset (p m). 2 ^ k * m)" using odd by (auto intro!: sum.reindex_cong[OF _ _ refl] inj_onI) also have "... = (\k\bitset (p m). 2 ^ k * m)" using assms(2)[of m] finite dual_order.trans in_bitset_bound by (fastforce intro!: sum.mono_neutral_cong_right) also have "... = (\k\bitset (p m). 2 ^ k) * m" by (subst sum_distrib_right) auto also have "... = p m * m" by (auto simp add: sum_bitset) finally have "(\i | \k. i = 2 ^ k * m \ i \ n. distinct_of_odd p i * i) = p m * m" . } note inner_eq = this have set_eq: "{i. 1 \ i \ i \ n} = \((\m. {i. \k. i = (2 ^ k) * m \ i \ n}) ` {m. m \ n \ odd m})" proof - { fix x assume "1 \ x" "x \ n" from this oddpart_leq[of x] have "oddpart x \ n \ odd (oddpart x) \ (\k. 2 ^ index x * oddpart x = 2 ^ k * oddpart x)" by (auto simp add: odd_oddpart) from this have "\m\n. odd m \ (\k. x = 2 ^ k * m)" by (auto simp add: index_oddpart_decomposition[symmetric]) } from this show ?thesis by (auto simp add: Suc_leI odd_pos) qed let ?S = "(\m. {i. \k. i = 2 ^ k * m \ i \ n}) ` {m. m \ n \ odd m}" have no_overlap: "\A\?S. \B\?S. A \ B \ A \ B = {}" by (auto simp add: index_oddpart_unique) have inj: "inj_on (\m. {i. (\k. i = 2 ^ k * m) \ i \ n}) {m. m \ n \ odd m}" unfolding inj_on_def by auto (force simp add: index_oddpart_unique) have reindex: "\F. (\i | 1 \ i \ i \ n. F i) = (\m | m \ n \ odd m. (\i | \k. i = 2 ^ k * m \ i \ n. F i))" unfolding set_eq by (subst sum.Union_disjoint) (auto simp add: no_overlap intro: sum.reindex_cong[OF inj]) have "(\i\n. distinct_of_odd p i * i) = (\i | 1 \ i \ i \ n. distinct_of_odd p i * i)" by (auto intro: sum.mono_neutral_right) also have "... = (\m | m \ n \ odd m. \i | \k. i = 2 ^ k * m \ i \ n. distinct_of_odd p i * i)" by (simp only: reindex) also have "... = (\i | i \ n \ odd i. p i * i)" by (rule sum.cong[OF refl]; subst inner_eq) auto also have "... = (\i\n. p i * i)" using assms(3) by (auto intro: sum.mono_neutral_left) finally show ?thesis . qed lemma leq_n: assumes "\i. 0 < p i \ 1 \ i \ i \ (n::nat)" assumes "(\i\n. p i * i) = n" shows "p i * i \ n" proof (rule ccontr) assume "\ p i * i \ n" from this have gr_n: "p i * i > n" by auto from this assms(1) have "1 \ i \ i \ n" by force from this have "(\j\n. p j * j) = p i * i + (\j | j \ n \ j \ i. p j * j)" by (subst sum.insert[symmetric]) (auto intro: sum.cong simp del: sum.insert) from this gr_n assms(2) show False by simp qed lemma distinct_of_odd_in_distinct_partitions: assumes "p \ {p. p partitions n \ (\i. p i \ 0 \ odd i)}" shows "distinct_of_odd p \ {p. p partitions n \ (\i. p i \ 1)}" proof have "distinct_of_odd p partitions n" proof (rule partitionsI) fix i assume "distinct_of_odd p i \ 0" from this assms show "1 \ i \ i \ n" unfolding partitions_def by (rule_tac distinct_of_odd) (auto simp add: leq_n) next from assms show "(\i\n. distinct_of_odd p i * i) = n" by (subst sum_distinct_of_odd) (auto simp add: distinct_distinct_of_odd leq_n elim: partitionsE) qed moreover have "\i. distinct_of_odd p i \ 1" by (intro allI distinct_distinct_of_odd) ultimately show "distinct_of_odd p partitions n \ (\i. distinct_of_odd p i \ 1)" by simp qed lemma odd_of_distinct_in_odd_partitions: assumes "p \ {p. p partitions n \ (\i. p i \ 1)}" shows "odd_of_distinct p \ {p. p partitions n \ (\i. p i \ 0 \ odd i)}" proof from assms have distinct: "\i. p i = 0 \ p i = 1" using le_imp_less_Suc less_Suc_eq_0_disj by fastforce from assms have set_eq: "{x. p x = 1} = {x \ {..n}. p x = 1}" unfolding partitions_def by auto from assms have sum: "(\i\n. p i * i) = n" unfolding partitions_def by auto { fix i assume i: "odd (i :: nat)" have 3: "inj_on index {x. p x = 1 \ oddpart x = i}" unfolding inj_on_def by auto (metis index_oddpart_decomposition) { fix j assume "p (2 ^ j * i) = 1" from this i have "j \ index ` {x. p x = 1 \ oddpart x = i}" by (auto simp add: index_oddpart(1, 2) intro!: image_eqI[where x="2 ^ j * i"]) } from i this have "{j. p (2 ^ j * i) = 1} = index ` {x. p x = 1 \ oddpart x = i}" by (auto simp add: index_oddpart_decomposition[symmetric]) from 3 this have "(\j | p (2 ^ j * i) = 1. 2 ^ j) * i = (\x | p x = 1 \ oddpart x = i. 2 ^ index x) * i" by (auto intro: sum.reindex_cong[where l = "index"]) also have "... = (\x | p x = 1 \ oddpart x = i. 2 ^ index x * oddpart x)" by (auto simp add: sum_distrib_right) also have "... = (\x | p x = 1 \ oddpart x = i. x)" by (simp only: index_oddpart_decomposition[symmetric]) also have "... \ (\x | p x = 1. x)" using set_eq by (intro sum_mono2) auto also have "... = (\x\n. p x * x)" using distinct by (subst set_eq) (force intro!: sum.mono_neutral_cong_left) also have "... = n" using sum . finally have "(\j | p (2 ^ j * i) = 1. 2 ^ j) * i \ n" . } from this have less_n: "\i. odd_of_distinct p i * i \ n" unfolding odd_of_distinct_def by auto have "odd_of_distinct p partitions n" proof (rule partitionsI) fix i assume "odd_of_distinct p i \ 0" from this assms show "1 \ i \ i \ n" by (elim CollectE conjE partitionsE odd_of_distinct) auto next have "(\i\n. odd_of_distinct p i * i) = (\i\n. distinct_of_odd (odd_of_distinct p) i * i)" using assms less_n by (subst sum_distinct_of_odd) (auto elim!: partitionsE odd_of_distinct simp only: odd) also have "... = (\i\n. p i * i)" using assms by (auto elim!: partitionsE simp only:) (subst distinct_odd, auto) also with assms have "... = n" by (auto elim: partitionsE) finally show "(\i\n. odd_of_distinct p i * i) = n" . qed moreover have "\i. odd_of_distinct p i \ 0 \ odd i" by (intro allI impI odd) ultimately show "odd_of_distinct p partitions n \ (\i. odd_of_distinct p i \ 0 \ odd i)" by simp qed subsection \Euler's Partition Theorem\ theorem Euler_partition_theorem: "card {p. p partitions n \ (\i. p i \ 1)} = card {p. p partitions n \ (\i. p i \ 0 \ odd i)}" (is "card ?distinct_partitions = card ?odd_partitions") proof (rule card_bij_eq) from odd_of_distinct_in_odd_partitions show "odd_of_distinct ` ?distinct_partitions \ ?odd_partitions" by auto moreover from distinct_of_odd_in_distinct_partitions show "distinct_of_odd ` ?odd_partitions \ ?distinct_partitions" by auto moreover have "\p\?distinct_partitions. distinct_of_odd (odd_of_distinct p) = p" by auto (subst distinct_odd; auto simp add: partitions_def) moreover have "\p\?odd_partitions. odd_of_distinct (distinct_of_odd p) = p" by auto (subst odd_distinct; auto simp add: partitions_def) ultimately show "inj_on odd_of_distinct ?distinct_partitions" "inj_on distinct_of_odd ?odd_partitions" by (intro bij_betw_imp_inj_on bij_betw_byWitness; auto)+ show "finite ?distinct_partitions" "finite ?odd_partitions" by (simp add: finite_partitions)+ qed end diff --git a/thys/UTP/utp/utp_pred.thy b/thys/UTP/utp/utp_pred.thy --- a/thys/UTP/utp/utp_pred.thy +++ b/thys/UTP/utp/utp_pred.thy @@ -1,613 +1,613 @@ section \ Alphabetised Predicates \ theory utp_pred imports utp_expr_funcs utp_subst utp_meta_subst utp_tactics begin text \ In this theory we begin to create an Isabelle version of the alphabetised predicate calculus that is described in Chapter 1 of the UTP book~\cite{Hoare&98}. \ subsection \ Predicate type and syntax \ text \ An alphabetised predicate is a simply a boolean valued expression. \ type_synonym '\ upred = "(bool, '\) uexpr" translations (type) "'\ upred" <= (type) "(bool, '\) uexpr" text \ We want to remain as close as possible to the mathematical UTP syntax, but also want to be conservative with HOL. For this reason we chose not to steal syntax from HOL, but where possible use polymorphism to allow selection of the appropriate operator (UTP vs. HOL). Thus we will first remove the standard syntax for conjunction, disjunction, and negation, and replace these with adhoc overloaded definitions. We similarly use polymorphic constants for the other predicate calculus operators. \ purge_notation conj (infixr "\" 35) and disj (infixr "\" 30) and Not ("\ _" [40] 40) consts utrue :: "'a" ("true") ufalse :: "'a" ("false") uconj :: "'a \ 'a \ 'a" (infixr "\" 35) udisj :: "'a \ 'a \ 'a" (infixr "\" 30) uimpl :: "'a \ 'a \ 'a" (infixr "\" 25) uiff :: "'a \ 'a \ 'a" (infixr "\" 25) unot :: "'a \ 'a" ("\ _" [40] 40) uex :: "('a \ '\) \ 'p \ 'p" uall :: "('a \ '\) \ 'p \ 'p" ushEx :: "['a \ 'p] \ 'p" ushAll :: "['a \ 'p] \ 'p" adhoc_overloading uconj conj and udisj disj and unot Not text \ We set up two versions of each of the quantifiers: @{const uex} / @{const uall} and @{const ushEx} / @{const ushAll}. The former pair allows quantification of UTP variables, whilst the latter allows quantification of HOL variables in concert with the literal expression constructor @{term "\x\"}. Both varieties will be needed at various points. Syntactically they are distinguished by a boldface quantifier for the HOL versions (achieved by the "bold" escape in Isabelle). \ nonterminal idt_list syntax "_idt_el" :: "idt \ idt_list" ("_") "_idt_list" :: "idt \ idt_list \ idt_list" ("(_,/ _)" [0, 1]) "_uex" :: "salpha \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_uall" :: "salpha \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_ushEx" :: "pttrn \ logic \ logic" ("\<^bold>\ _ \ _" [0, 10] 10) "_ushAll" :: "pttrn \ logic \ logic" ("\<^bold>\ _ \ _" [0, 10] 10) "_ushBEx" :: "pttrn \ logic \ logic \ logic" ("\<^bold>\ _ \ _ \ _" [0, 0, 10] 10) "_ushBAll" :: "pttrn \ logic \ logic \ logic" ("\<^bold>\ _ \ _ \ _" [0, 0, 10] 10) "_ushGAll" :: "pttrn \ logic \ logic \ logic" ("\<^bold>\ _ | _ \ _" [0, 0, 10] 10) "_ushGtAll" :: "idt \ logic \ logic \ logic" ("\<^bold>\ _ > _ \ _" [0, 0, 10] 10) "_ushLtAll" :: "idt \ logic \ logic \ logic" ("\<^bold>\ _ < _ \ _" [0, 0, 10] 10) "_uvar_res" :: "logic \ salpha \ logic" (infixl "\\<^sub>v" 90) translations "_uex x P" == "CONST uex x P" "_uex (_salphaset (_salphamk (x +\<^sub>L y))) P" <= "_uex (x +\<^sub>L y) P" "_uall x P" == "CONST uall x P" "_uall (_salphaset (_salphamk (x +\<^sub>L y))) P" <= "_uall (x +\<^sub>L y) P" "_ushEx x P" == "CONST ushEx (\ x. P)" "\<^bold>\ x \ A \ P" => "\<^bold>\ x \ \x\ \\<^sub>u A \ P" "_ushAll x P" == "CONST ushAll (\ x. P)" "\<^bold>\ x \ A \ P" => "\<^bold>\ x \ \x\ \\<^sub>u A \ P" "\<^bold>\ x | P \ Q" => "\<^bold>\ x \ P \ Q" "\<^bold>\ x > y \ P" => "\<^bold>\ x \ \x\ >\<^sub>u y \ P" "\<^bold>\ x < y \ P" => "\<^bold>\ x \ \x\ <\<^sub>u y \ P" subsection \ Predicate operators \ text \ We chose to maximally reuse definitions and laws built into HOL. For this reason, when introducing the core operators we proceed by lifting operators from the polymorphic algebraic hierarchy of HOL. Thus the initial definitions take place in the context of type class instantiations. We first introduce our own class called \emph{refine} that will add the refinement operator syntax to the HOL partial order class. \ class refine = order abbreviation refineBy :: "'a::refine \ 'a \ bool" (infix "\" 50) where "P \ Q \ less_eq Q P" text \ Since, on the whole, lattices in UTP are the opposite way up to the standard definitions in HOL, we syntactically invert the lattice operators. This is the one exception where we do steal HOL syntax, but I think it makes sense for UTP. Indeed we make this inversion for all of the lattice operators. \ purge_notation Lattices.inf (infixl "\" 70) notation Lattices.inf (infixl "\" 70) purge_notation Lattices.sup (infixl "\" 65) notation Lattices.sup (infixl "\" 65) purge_notation Inf ("\_" [900] 900) notation Inf ("\_" [900] 900) purge_notation Sup ("\_" [900] 900) notation Sup ("\_" [900] 900) purge_notation Orderings.bot ("\") notation Orderings.bot ("\") purge_notation Orderings.top ("\") notation Orderings.top ("\") purge_syntax "_INF1" :: "pttrns \ 'b \ 'b" ("(3\_./ _)" [0, 10] 10) "_INF" :: "pttrn \ 'a set \ 'b \ 'b" ("(3\_\_./ _)" [0, 0, 10] 10) "_SUP1" :: "pttrns \ 'b \ 'b" ("(3\_./ _)" [0, 10] 10) "_SUP" :: "pttrn \ 'a set \ 'b \ 'b" ("(3\_\_./ _)" [0, 0, 10] 10) syntax "_INF1" :: "pttrns \ 'b \ 'b" ("(3\_./ _)" [0, 10] 10) "_INF" :: "pttrn \ 'a set \ 'b \ 'b" ("(3\_\_./ _)" [0, 0, 10] 10) "_SUP1" :: "pttrns \ 'b \ 'b" ("(3\_./ _)" [0, 10] 10) "_SUP" :: "pttrn \ 'a set \ 'b \ 'b" ("(3\_\_./ _)" [0, 0, 10] 10) text \ We trivially instantiate our refinement class \ instance uexpr :: (order, type) refine .. \ \ Configure transfer law for refinement for the fast relational tactics. \ theorem upred_ref_iff [uexpr_transfer_laws]: "(P \ Q) = (\b. \Q\\<^sub>e b \ \P\\<^sub>e b)" apply (transfer) apply (clarsimp) done text \ Next we introduce the lattice operators, which is again done by lifting. \ instantiation uexpr :: (lattice, type) lattice begin lift_definition sup_uexpr :: "('a, 'b) uexpr \ ('a, 'b) uexpr \ ('a, 'b) uexpr" is "\P Q A. Lattices.sup (P A) (Q A)" . lift_definition inf_uexpr :: "('a, 'b) uexpr \ ('a, 'b) uexpr \ ('a, 'b) uexpr" is "\P Q A. Lattices.inf (P A) (Q A)" . instance by (intro_classes) (transfer, auto)+ end instantiation uexpr :: (bounded_lattice, type) bounded_lattice begin lift_definition bot_uexpr :: "('a, 'b) uexpr" is "\ A. Orderings.bot" . lift_definition top_uexpr :: "('a, 'b) uexpr" is "\ A. Orderings.top" . instance by (intro_classes) (transfer, auto)+ end lemma top_uexpr_rep_eq [simp]: "\Orderings.bot\\<^sub>e b = False" by (transfer, auto) lemma bot_uexpr_rep_eq [simp]: "\Orderings.top\\<^sub>e b = True" by (transfer, auto) instance uexpr :: (distrib_lattice, type) distrib_lattice by (intro_classes) (transfer, rule ext, auto simp add: sup_inf_distrib1) text \ Finally we show that predicates form a Boolean algebra (under the lattice operators), a complete lattice, a completely distribute lattice, and a complete boolean algebra. This equip us with a very complete theory for basic logical propositions. \ instance uexpr :: (boolean_algebra, type) boolean_algebra apply (intro_classes, unfold uexpr_defs; transfer, rule ext) apply (simp_all add: sup_inf_distrib1 diff_eq) done instantiation uexpr :: (complete_lattice, type) complete_lattice begin lift_definition Inf_uexpr :: "('a, 'b) uexpr set \ ('a, 'b) uexpr" - is "\ PS A. INF P:PS. P(A)" . + is "\ PS A. INF P\PS. P(A)" . lift_definition Sup_uexpr :: "('a, 'b) uexpr set \ ('a, 'b) uexpr" - is "\ PS A. SUP P:PS. P(A)" . + is "\ PS A. SUP P\PS. P(A)" . instance by (intro_classes) (transfer, auto intro: INF_lower SUP_upper simp add: INF_greatest SUP_least)+ end instance uexpr :: (complete_distrib_lattice, type) complete_distrib_lattice by (intro_classes; transfer; auto simp add: INF_SUP_set) instance uexpr :: (complete_boolean_algebra, type) complete_boolean_algebra .. text \ From the complete lattice, we can also define and give syntax for the fixed-point operators. Like the lattice operators, these are reversed in UTP. \ syntax "_mu" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_nu" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) notation gfp ("\") notation lfp ("\") translations "\ X \ P" == "CONST lfp (\ X. P)" "\ X \ P" == "CONST gfp (\ X. P)" text \ With the lattice operators defined, we can proceed to give definitions for the standard predicate operators in terms of them. \ definition "true_upred = (Orderings.top :: '\ upred)" definition "false_upred = (Orderings.bot :: '\ upred)" definition "conj_upred = (Lattices.inf :: '\ upred \ '\ upred \ '\ upred)" definition "disj_upred = (Lattices.sup :: '\ upred \ '\ upred \ '\ upred)" definition "not_upred = (uminus :: '\ upred \ '\ upred)" definition "diff_upred = (minus :: '\ upred \ '\ upred \ '\ upred)" abbreviation Conj_upred :: "'\ upred set \ '\ upred" ("\_" [900] 900) where "\ A \ \ A" abbreviation Disj_upred :: "'\ upred set \ '\ upred" ("\_" [900] 900) where "\ A \ \ A" notation conj_upred (infixr "\\<^sub>p" 35) and disj_upred (infixr "\\<^sub>p" 30) text \ Perhaps slightly confusingly, the UTP infimum is the HOL supremum and vice-versa. This is because, again, in UTP the lattice is inverted due to the definition of refinement and a desire to have miracle at the top, and abort at the bottom. \ lift_definition UINF :: "('a \ '\ upred) \ ('a \ ('b::complete_lattice, '\) uexpr) \ ('b, '\) uexpr" is "\ P F b. Sup {\F x\\<^sub>eb | x. \P x\\<^sub>eb}" . lift_definition USUP :: "('a \ '\ upred) \ ('a \ ('b::complete_lattice, '\) uexpr) \ ('b, '\) uexpr" is "\ P F b. Inf {\F x\\<^sub>eb | x. \P x\\<^sub>eb}" . syntax "_USup" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_USup" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_USup_mem" :: "pttrn \ logic \ logic \ logic" ("\ _ \ _ \ _" [0, 10] 10) "_USup_mem" :: "pttrn \ logic \ logic \ logic" ("\ _ \ _ \ _" [0, 10] 10) "_USUP" :: "pttrn \ logic \ logic \ logic" ("\ _ | _ \ _" [0, 0, 10] 10) "_USUP" :: "pttrn \ logic \ logic \ logic" ("\ _ | _ \ _" [0, 0, 10] 10) "_UInf" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_UInf" :: "pttrn \ logic \ logic" ("\ _ \ _" [0, 10] 10) "_UInf_mem" :: "pttrn \ logic \ logic \ logic" ("\ _ \ _ \ _" [0, 10] 10) "_UInf_mem" :: "pttrn \ logic \ logic \ logic" ("\ _ \ _ \ _" [0, 10] 10) "_UINF" :: "pttrn \ logic \ logic \ logic" ("\ _ | _ \ _" [0, 10] 10) "_UINF" :: "pttrn \ logic \ logic \ logic" ("\ _ | _ \ _" [0, 10] 10) translations "\ x | P \ F" => "CONST UINF (\ x. P) (\ x. F)" "\ x \ F" == "\ x | true \ F" "\ x \ F" == "\ x | true \ F" "\ x \ A \ F" => "\ x | \x\ \\<^sub>u \A\ \ F" "\ x \ A \ F" <= "\ x | \y\ \\<^sub>u \A\ \ F" "\ x | P \ F" <= "CONST UINF (\ y. P) (\ x. F)" "\ x | P \ F(x)" <= "CONST UINF (\ x. P) F" "\ x | P \ F" => "CONST USUP (\ x. P) (\ x. F)" "\ x \ F" == "\ x | true \ F" "\ x \ A \ F" => "\ x | \x\ \\<^sub>u \A\ \ F" "\ x \ A \ F" <= "\ x | \y\ \\<^sub>u \A\ \ F" "\ x | P \ F" <= "CONST USUP (\ y. P) (\ x. F)" "\ x | P \ F(x)" <= "CONST USUP (\ x. P) F" text \ We also define the other predicate operators \ lift_definition impl::"'\ upred \ '\ upred \ '\ upred" is "\ P Q A. P A \ Q A" . lift_definition iff_upred ::"'\ upred \ '\ upred \ '\ upred" is "\ P Q A. P A \ Q A" . lift_definition ex :: "('a \ '\) \ '\ upred \ '\ upred" is "\ x P b. (\ v. P(put\<^bsub>x\<^esub> b v))" . lift_definition shEx ::"['\ \'\ upred] \ '\ upred" is "\ P A. \ x. (P x) A" . lift_definition all :: "('a \ '\) \ '\ upred \ '\ upred" is "\ x P b. (\ v. P(put\<^bsub>x\<^esub> b v))" . lift_definition shAll ::"['\ \'\ upred] \ '\ upred" is "\ P A. \ x. (P x) A" . text \ We define the following operator which is dual of existential quantification. It hides the valuation of variables other than $x$ through existential quantification. \ lift_definition var_res :: "'\ upred \ ('a \ '\) \ '\ upred" is "\ P x b. \ b'. P (b' \\<^sub>L b on x)" . translations "_uvar_res P a" \ "CONST var_res P a" text \ We have to add a u subscript to the closure operator as I don't want to override the syntax for HOL lists (we'll be using them later). \ lift_definition closure::"'\ upred \ '\ upred" ("[_]\<^sub>u") is "\ P A. \A'. P A'" . lift_definition taut :: "'\ upred \ bool" ("`_`") is "\ P. \ A. P A" . text \ Configuration for UTP tactics \ update_uexpr_rep_eq_thms \ \ Reread @{text rep_eq} theorems. \ declare utp_pred.taut.rep_eq [upred_defs] adhoc_overloading utrue "true_upred" and ufalse "false_upred" and unot "not_upred" and uconj "conj_upred" and udisj "disj_upred" and uimpl impl and uiff iff_upred and uex ex and uall all and ushEx shEx and ushAll shAll syntax "_uneq" :: "logic \ logic \ logic" (infixl "\\<^sub>u" 50) "_unmem" :: "('a, '\) uexpr \ ('a set, '\) uexpr \ (bool, '\) uexpr" (infix "\\<^sub>u" 50) translations "x \\<^sub>u y" == "CONST unot (x =\<^sub>u y)" "x \\<^sub>u A" == "CONST unot (CONST bop (\) x A)" declare true_upred_def [upred_defs] declare false_upred_def [upred_defs] declare conj_upred_def [upred_defs] declare disj_upred_def [upred_defs] declare not_upred_def [upred_defs] declare diff_upred_def [upred_defs] declare subst_upd_uvar_def [upred_defs] declare cond_subst_def [upred_defs] declare par_subst_def [upred_defs] declare subst_del_def [upred_defs] declare unrest_usubst_def [upred_defs] declare uexpr_defs [upred_defs] lemma true_alt_def: "true = \True\" by (pred_auto) lemma false_alt_def: "false = \False\" by (pred_auto) declare true_alt_def[THEN sym,simp] declare false_alt_def[THEN sym,simp] subsection \ Unrestriction Laws \ lemma unrest_allE: "\ \ \ P; P = true \ Q; P = false \ Q \ \ Q" by (pred_auto) lemma unrest_true [unrest]: "x \ true" by (pred_auto) lemma unrest_false [unrest]: "x \ false" by (pred_auto) lemma unrest_conj [unrest]: "\ x \ (P :: '\ upred); x \ Q \ \ x \ P \ Q" by (pred_auto) lemma unrest_disj [unrest]: "\ x \ (P :: '\ upred); x \ Q \ \ x \ P \ Q" by (pred_auto) lemma unrest_UINF [unrest]: "\ (\ i. x \ P(i)); (\ i. x \ Q(i)) \ \ x \ (\ i | P(i) \ Q(i))" by (pred_auto) lemma unrest_USUP [unrest]: "\ (\ i. x \ P(i)); (\ i. x \ Q(i)) \ \ x \ (\ i | P(i) \ Q(i))" by (pred_auto) lemma unrest_UINF_mem [unrest]: "\(\ i. i \ A \ x \ P(i)) \ \ x \ (\ i\A \ P(i))" by (pred_simp, metis) lemma unrest_USUP_mem [unrest]: "\(\ i. i \ A \ x \ P(i)) \ \ x \ (\ i\A \ P(i))" by (pred_simp, metis) lemma unrest_impl [unrest]: "\ x \ P; x \ Q \ \ x \ P \ Q" by (pred_auto) lemma unrest_iff [unrest]: "\ x \ P; x \ Q \ \ x \ P \ Q" by (pred_auto) lemma unrest_not [unrest]: "x \ (P :: '\ upred) \ x \ (\ P)" by (pred_auto) text \ The sublens proviso can be thought of as membership below. \ lemma unrest_ex_in [unrest]: "\ mwb_lens y; x \\<^sub>L y \ \ x \ (\ y \ P)" by (pred_auto) declare sublens_refl [simp] declare lens_plus_ub [simp] declare lens_plus_right_sublens [simp] declare comp_wb_lens [simp] declare comp_mwb_lens [simp] declare plus_mwb_lens [simp] lemma unrest_ex_diff [unrest]: assumes "x \ y" "y \ P" shows "y \ (\ x \ P)" using assms lens_indep_comm by (rel_simp', fastforce) lemma unrest_all_in [unrest]: "\ mwb_lens y; x \\<^sub>L y \ \ x \ (\ y \ P)" by (pred_auto) lemma unrest_all_diff [unrest]: assumes "x \ y" "y \ P" shows "y \ (\ x \ P)" using assms by (pred_simp, simp_all add: lens_indep_comm) lemma unrest_var_res_diff [unrest]: assumes "x \ y" shows "y \ (P \\<^sub>v x)" using assms by (pred_auto) lemma unrest_var_res_in [unrest]: assumes "mwb_lens x" "y \\<^sub>L x" "y \ P" shows "y \ (P \\<^sub>v x)" using assms apply (pred_auto) apply fastforce apply (metis (no_types, lifting) mwb_lens_weak weak_lens.put_get) done lemma unrest_shEx [unrest]: assumes "\ y. x \ P(y)" shows "x \ (\<^bold>\ y \ P(y))" using assms by (pred_auto) lemma unrest_shAll [unrest]: assumes "\ y. x \ P(y)" shows "x \ (\<^bold>\ y \ P(y))" using assms by (pred_auto) lemma unrest_closure [unrest]: "x \ [P]\<^sub>u" by (pred_auto) subsection \ Used-by laws \ lemma usedBy_not [unrest]: "\ x \ P \ \ x \ (\ P)" by (pred_simp) lemma usedBy_conj [unrest]: "\ x \ P; x \ Q \ \ x \ (P \ Q)" by (pred_simp) lemma usedBy_disj [unrest]: "\ x \ P; x \ Q \ \ x \ (P \ Q)" by (pred_simp) lemma usedBy_impl [unrest]: "\ x \ P; x \ Q \ \ x \ (P \ Q)" by (pred_simp) lemma usedBy_iff [unrest]: "\ x \ P; x \ Q \ \ x \ (P \ Q)" by (pred_simp) subsection \ Substitution Laws \ text \ Substitution is monotone \ lemma subst_mono: "P \ Q \ (\ \ P) \ (\ \ Q)" by (pred_auto) lemma subst_true [usubst]: "\ \ true = true" by (pred_auto) lemma subst_false [usubst]: "\ \ false = false" by (pred_auto) lemma subst_not [usubst]: "\ \ (\ P) = (\ \ \ P)" by (pred_auto) lemma subst_impl [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_iff [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_disj [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_conj [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_sup [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_inf [usubst]: "\ \ (P \ Q) = (\ \ P \ \ \ Q)" by (pred_auto) lemma subst_UINF [usubst]: "\ \ (\ i | P(i) \ Q(i)) = (\ i | (\ \ P(i)) \ (\ \ Q(i)))" by (pred_auto) lemma subst_USUP [usubst]: "\ \ (\ i | P(i) \ Q(i)) = (\ i | (\ \ P(i)) \ (\ \ Q(i)))" by (pred_auto) lemma subst_closure [usubst]: "\ \ [P]\<^sub>u = [P]\<^sub>u" by (pred_auto) lemma subst_shEx [usubst]: "\ \ (\<^bold>\ x \ P(x)) = (\<^bold>\ x \ \ \ P(x))" by (pred_auto) lemma subst_shAll [usubst]: "\ \ (\<^bold>\ x \ P(x)) = (\<^bold>\ x \ \ \ P(x))" by (pred_auto) text \ TODO: Generalise the quantifier substitution laws to n-ary substitutions \ lemma subst_ex_same [usubst]: "mwb_lens x \ \(x \\<^sub>s v) \ (\ x \ P) = \ \ (\ x \ P)" by (pred_auto) lemma subst_ex_same' [usubst]: "mwb_lens x \ \(x \\<^sub>s v) \ (\ &x \ P) = \ \ (\ &x \ P)" by (pred_auto) lemma subst_ex_indep [usubst]: assumes "x \ y" "y \ v" shows "(\ y \ P)\v/x\ = (\ y \ P\v/x\)" using assms apply (pred_auto) using lens_indep_comm apply fastforce+ done lemma subst_ex_unrest [usubst]: "x \ \ \ \ \ (\ x \ P) = (\ x \ \ \ P)" by (pred_auto) lemma subst_all_same [usubst]: "mwb_lens x \ \(x \\<^sub>s v) \ (\ x \ P) = \ \ (\ x \ P)" by (simp add: id_subst subst_unrest unrest_all_in) lemma subst_all_indep [usubst]: assumes "x \ y" "y \ v" shows "(\ y \ P)\v/x\ = (\ y \ P\v/x\)" using assms by (pred_simp, simp_all add: lens_indep_comm) lemma msubst_true [usubst]: "true\x\v\ = true" by (pred_auto) lemma msubst_false [usubst]: "false\x\v\ = false" by (pred_auto) lemma msubst_not [usubst]: "(\ P(x))\x\v\ = (\ ((P x)\x\v\))" by (pred_auto) lemma msubst_not_2 [usubst]: "(\ P x y)\(x,y)\v\ = (\ ((P x y)\(x,y)\v\))" by (pred_auto)+ lemma msubst_disj [usubst]: "(P(x) \ Q(x))\x\v\ = ((P(x))\x\v\ \ (Q(x))\x\v\)" by (pred_auto) lemma msubst_disj_2 [usubst]: "(P x y \ Q x y)\(x,y)\v\ = ((P x y)\(x,y)\v\ \ (Q x y)\(x,y)\v\)" by (pred_auto)+ lemma msubst_conj [usubst]: "(P(x) \ Q(x))\x\v\ = ((P(x))\x\v\ \ (Q(x))\x\v\)" by (pred_auto) lemma msubst_conj_2 [usubst]: "(P x y \ Q x y)\(x,y)\v\ = ((P x y)\(x,y)\v\ \ (Q x y)\(x,y)\v\)" by (pred_auto)+ lemma msubst_implies [usubst]: "(P x \ Q x)\x\v\ = ((P x)\x\v\ \ (Q x)\x\v\)" by (pred_auto) lemma msubst_implies_2 [usubst]: "(P x y \ Q x y)\(x,y)\v\ = ((P x y)\(x,y)\v\ \ (Q x y)\(x,y)\v\)" by (pred_auto)+ lemma msubst_shAll [usubst]: "(\<^bold>\ x \ P x y)\y\v\ = (\<^bold>\ x \ (P x y)\y\v\)" by (pred_auto) lemma msubst_shAll_2 [usubst]: "(\<^bold>\ x \ P x y z)\(y,z)\v\ = (\<^bold>\ x \ (P x y z)\(y,z)\v\)" by (pred_auto)+ subsection \ Sandbox for conjectures \ definition utp_sandbox :: "'\ upred \ bool" ("TRY'(_')") where "TRY(P) = (P = undefined)" translations "P" <= "CONST utp_sandbox P" end \ No newline at end of file