section ‹Fractional Predicates and Magic Wands in Automatic Separation Logic Verifiers› text ‹This section corresponds to Section 5 of the paper~\<^cite>‹"UnboundedSL"›.› theory AutomaticVerifiers imports FixedPoint WandProperties begin context logic begin subsection ‹Syntactic multiplication› text ‹The following definition corresponds to Figure 6 of the paper~\<^cite>‹"UnboundedSL"›.› fun syn_mult :: "'b ⇒ ('a, 'b, 'c, 'd) assertion ⇒ ('a, 'b, 'c, 'd) assertion" where "syn_mult π (Star A B) = Star (syn_mult π A) (syn_mult π B)" | "syn_mult π (Wand A B) = Wand (syn_mult π A) (syn_mult π B)" | "syn_mult π (Or A B) = Or (syn_mult π A) (syn_mult π B)" | "syn_mult π (And A B) = And (syn_mult π A) (syn_mult π B)" | "syn_mult π (Imp A B) = Imp (syn_mult π A) (syn_mult π B)" | "syn_mult π (Mult α A) = syn_mult (smult α π) A" | "syn_mult π (Exists x A) = Exists x (syn_mult π A)" | "syn_mult π (Forall x A) = Forall x (syn_mult π A)" | "syn_mult π (Wildcard A) = Wildcard A" | "syn_mult π A = Mult π A" definition div_state where "div_state π σ = (SOME r. σ = π ⊙ r)" lemma div_state_ok: "σ = π ⊙ (div_state π σ)" by (metis (mono_tags) div_state_def someI_ex unique_inv) text ‹The following theorem corresponds to Theorem 6 of the paper~\<^cite>‹"UnboundedSL"›.› theorem syn_sen_mult_same: "σ, s, Δ ⊨ syn_mult π A ⟷ σ, s, Δ ⊨ Mult π A" proof (induct A arbitrary: σ π s) case (Exists x A) show ?case (is "?A ⟷ ?B") proof show "?B ⟹ ?A" using Exists.hyps by auto show "?A ⟹ ?B" using Exists.hyps by fastforce qed next case (Forall x A) then show ?case by (metis dot_forall1 dot_forall2 entails_def sat.simps(9) syn_mult.simps(8)) next case (Star A B) show ?case (is "?P ⟷ ?Q") proof show "?P ⟹ ?Q" proof - assume ?P then obtain a b where "a, s, Δ ⊨ syn_mult π A" "b, s, Δ ⊨ syn_mult π B" "Some σ = a ⊕ b" by auto then obtain "a, s, Δ ⊨ Mult π A" "b, s, Δ ⊨ Mult π B" using Star.hyps(1) Star.hyps(2) Star.prems by blast then show ?Q by (meson ‹Some σ = a ⊕ b› dot_star2 entails_def sat.simps(2)) qed assume ?Q then obtain a b where "a, s, Δ ⊨ Mult π A" "b, s, Δ ⊨ Mult π B" "Some σ = a ⊕ b" by (meson dot_star1 entails_def sat.simps(2)) then show ?P using Star.hyps(1) Star.hyps(2) Star.prems by force qed next case (Mult p A) show ?case (is "?P ⟷ ?Q") proof show "?P ⟹ ?Q" proof - assume ?P then have "σ, s, Δ ⊨ syn_mult (smult p π) A" by auto then have "σ, s, Δ ⊨ Mult (smult p π) A" using Mult.hyps by blast then show ?Q by (metis dot_mult2 logic.entails_def logic_axioms smult_comm) qed assume ?Q then obtain a where "a, s, Δ ⊨ A" "σ = π ⊙ (p ⊙ a)" by auto then show ?P using Mult.hyps double_mult smult_comm by auto qed next case (Wand A B) show ?case (is "?P ⟷ ?Q") proof show "?P ⟹ ?Q" proof - assume "σ, s, Δ ⊨ syn_mult π (Wand A B)" then have "σ, s, Δ ⊨ Wand (syn_mult π A) (syn_mult π B)" by auto moreover have "div_state π σ, s, Δ ⊨ Wand A B" proof (rule sat_wand) fix a b assume "a, s, Δ ⊨ A ∧ Some b = div_state π σ ⊕ a" then have "Some (π ⊙ b) = σ ⊕ (π ⊙ a)" using div_state_ok plus_mult by presburger moreover have "π ⊙ a, s, Δ ⊨ Mult π A" using ‹a, s, Δ ⊨ A ∧ Some b = div_state π σ ⊕ a› by auto then have "π ⊙ a, s, Δ ⊨ syn_mult π A" using Wand.hyps(1) Wand.prems by blast then have "π ⊙ b, s, Δ ⊨ syn_mult π B" using ‹σ, s, Δ ⊨ Wand (syn_mult π A) (syn_mult π B)› calculation by auto ultimately show "b, s, Δ ⊨ B" by (metis Wand.hyps(2) Wand.prems can_divide sat.simps(1)) qed then show "σ, s, Δ ⊨ Mult π (Wand A B)" by (metis div_state_ok sat.simps(1)) qed assume "σ, s, Δ ⊨ Mult π (Wand A B)" then have "div_state π σ, s, Δ ⊨ Wand A B" by (metis div_state_ok can_divide sat.simps(1)) have "σ, s, Δ ⊨ Wand (syn_mult π A) (syn_mult π B)" proof (rule sat_wand) fix a b assume "a, s, Δ ⊨ syn_mult π A ∧ Some b = σ ⊕ a" then have "Some (div_state π b) = div_state π σ ⊕ div_state π a" by (metis div_state_ok plus_mult unique_inv) then have "div_state π b, s, Δ ⊨ B" by (metis (no_types, lifting) Wand.hyps(1) ‹a, s, Δ ⊨ syn_mult π A ∧ Some b = σ ⊕ a› ‹div_state π σ, s, Δ ⊨ Wand A B› div_state_ok logic.can_divide logic_axioms sat.simps(1) sat.simps(3)) then show "b, s, Δ ⊨ syn_mult π B" using Wand.hyps(2) div_state_ok sat.simps(1) by blast qed then show "σ, s, Δ ⊨ syn_mult π (Wand A B)" by simp qed next case (And A B) show ?case (is "?P ⟷ ?Q") proof show "?P ⟹ ?Q" proof - assume ?P then obtain "σ, s, Δ ⊨ syn_mult π A" "σ, s, Δ ⊨ syn_mult π B" by auto then show ?Q by (meson And.hyps(1) And.hyps(2) dot_and2 logic.entails_def logic_axioms sat.simps(7)) qed assume ?Q then show ?P using And.hyps(1) And.hyps(2) And.prems by auto qed next case (Imp A B) show ?case (is "?P ⟷ ?Q") proof show "?P ⟹ ?Q" by (metis Imp.hyps(1) Imp.hyps(2) sat.simps(1) sat.simps(5) syn_mult.simps(5) unique_inv) assume ?Q then show ?P by (metis Imp.hyps(1) Imp.hyps(2) Imp.prems can_divide sat.simps(1) sat.simps(5) syn_mult.simps(5)) qed next case (Wildcard A) then show ?case by (metis DotWild entails_def equivalent_def syn_mult.simps(9)) qed (auto) subsection ‹Monotonicity and fixed point› (* Bool means positive *) fun pos_neg_rec_call :: "bool ⇒ ('a, 'b, 'c, 'd) assertion ⇒ bool" where "pos_neg_rec_call b Pred ⟷ b" | "pos_neg_rec_call b (Mult _ A) ⟷ pos_neg_rec_call b A" | "pos_neg_rec_call b (Exists _ A) ⟷ pos_neg_rec_call b A" | "pos_neg_rec_call b (Forall _ A) ⟷ pos_neg_rec_call b A" | "pos_neg_rec_call b (Star A B) ⟷ pos_neg_rec_call b A ∧ pos_neg_rec_call b B" | "pos_neg_rec_call b (Or A B) ⟷ pos_neg_rec_call b A ∧ pos_neg_rec_call b B" | "pos_neg_rec_call b (And A B) ⟷ pos_neg_rec_call b A ∧ pos_neg_rec_call b B" | "pos_neg_rec_call b (Wand A B) ⟷ pos_neg_rec_call (¬ b) A ∧ pos_neg_rec_call b B" | "pos_neg_rec_call b (Imp A B) ⟷ pos_neg_rec_call (¬ b) A ∧ pos_neg_rec_call b B" | "pos_neg_rec_call _ (Sem _) ⟷ True" | "pos_neg_rec_call b (Bounded A) ⟷ pos_neg_rec_call b A" | "pos_neg_rec_call b (Wildcard A) ⟷ pos_neg_rec_call b A" lemma pos_neg_rec_call_mono: assumes "pos_neg_rec_call b A" shows "(b ⟶ monotonic (applies_eq A)) ∧ (¬ b ⟶ non_increasing (applies_eq A))" using assms proof (induct A arbitrary: b) case (Exists x A) then show ?case by (meson mono_exists non_increasing_exists pos_neg_rec_call.simps(3)) next case (Forall x A) then show ?case by (meson mono_forall non_increasing_forall pos_neg_rec_call.simps(4)) next case (Sem x) then show ?case by (metis applies_eq.simps mem_Collect_eq mono_sem non_increasingI sat.simps(4) smaller_interp_def subsetI) next case (Mult x1a A) then show ?case using mono_mult non_increasing_mult pos_neg_rec_call.simps(2) by blast next case (Star A1 A2) then show ?case by (metis mono_star non_inc_star pos_neg_rec_call.simps(5)) next case (Wand A1 A2) then show ?case by (metis mono_wand non_increasing_wand pos_neg_rec_call.simps(8)) next case (Or A1 A2) then show ?case by (metis mono_or non_increasing_or pos_neg_rec_call.simps(6)) next case (And A1 A2) then show ?case by (metis mono_and non_increasing_and pos_neg_rec_call.simps(7)) next case (Imp A1 A2) then show ?case by (metis mono_imp non_increasing_imp pos_neg_rec_call.simps(9)) next case Pred then show ?case using mono_interp pos_neg_rec_call.simps(1) by blast next case (Bounded A) then show ?case using mono_bounded non_increasing_bounded pos_neg_rec_call.simps(11) by blast next case (Wildcard A) then show ?case using mono_wild non_increasing_wild pos_neg_rec_call.simps(12) by blast qed text ‹The following theorem corresponds to Theorem 7 of the paper~\<^cite>‹"UnboundedSL"›.› theorem exists_lfp_gfp: assumes "pos_neg_rec_call True A" shows "σ, s, LFP (applies_eq A) ⊨ A ⟷ σ ∈ LFP (applies_eq A) s" and "σ, s, GFP (applies_eq A) ⊨ A ⟷ σ ∈ GFP (applies_eq A) s" apply (metis LFP_is_FP applies_eq.simps assms mem_Collect_eq pos_neg_rec_call_mono) by (metis GFP_is_FP applies_eq.simps assms mem_Collect_eq pos_neg_rec_call_mono) subsection ‹Combinability› definition combinable_sem :: "(('d ⇒ 'c) ⇒ 'a ⇒ bool) ⇒ bool" where "combinable_sem B ⟷ (∀a b x s α β. B s a ∧ B s b ∧ sadd α β = one ∧ Some x = α ⊙ a ⊕ β ⊙ b ⟶ B s x)" fun wf_assertion :: "('a, 'b, 'c, 'd) assertion ⇒ bool" where "wf_assertion Pred ⟷ True" | "wf_assertion (Sem B) ⟷ combinable_sem B" | "wf_assertion (Mult _ A) ⟷ wf_assertion A" | "wf_assertion (Forall _ A) ⟷ wf_assertion A" | "wf_assertion (Exists x A) ⟷ wf_assertion A ∧ (∀Δ. unambiguous Δ A x)" | "wf_assertion (Star A B) ⟷ wf_assertion A ∧ wf_assertion B" | "wf_assertion (And A B) ⟷ wf_assertion A ∧ wf_assertion B" | "wf_assertion (Wand A B) ⟷ wf_assertion B" | "wf_assertion (Imp A B) ⟷ pure A ∧ wf_assertion B" | "wf_assertion (Wildcard A) ⟷ wf_assertion A" | "wf_assertion _ ⟷ False" lemma wf_implies_combinable: assumes "wf_assertion A" and "sem_combinable Δ" shows "combinable Δ A" using assms proof (induct A) case (Exists x A) then show ?case by (meson combinable_exists wf_assertion.simps(5)) next case (Forall x A) then show ?case by (meson combinable_forall wf_assertion.simps(4)) next case (Sem B) show ?case proof (rule combinableI) fix a b p q x σ s assume "a, s, Δ ⊨ Sem B ∧ b, s, Δ ⊨ Sem B ∧ Some x = p ⊙ a ⊕ q ⊙ b ∧ sadd p q = one" then show "x, s, Δ ⊨ Sem B" by (metis Sem.prems(1) combinable_sem_def sat.simps(4) wf_assertion.simps(2)) qed next case (Mult x1a A) then show ?case using combinable_mult wf_assertion.simps(3) by blast next case (Star A1 A2) then show ?case using combinable_star wf_assertion.simps(6) by blast next case (Wand A1 A2) then show ?case using combinable_wand wf_assertion.simps(8) by blast next case (And A1 A2) then show ?case using combinable_and by auto next case (Imp A1 A2) then show ?case using combinable_imp by auto next case Pred show ?case proof (rule combinableI) fix a b p q x σ s assume "a, s, Δ ⊨ Pred ∧ b, s, Δ ⊨ Pred ∧ Some x = p ⊙ a ⊕ q ⊙ b ∧ sadd p q = one" then show "x, s, Δ ⊨ Pred" using assms(2) sat.simps(10) sem_combinableE by metis qed next case (Wildcard A) then show ?case using combinable_wildcard wf_assertion.simps(10) by blast qed (auto) subsection ‹Theorems› text ‹The following two theorems correspond to the rules shown in Section 5.1 of the paper~\<^cite>‹"UnboundedSL"›.› theorem apply_wand: "Star (syn_mult π A) (Mult π (Wand A B)), Δ ⊢ syn_mult π B" proof (rule entailsI) fix σ s assume asm: "σ, s, Δ ⊨ Star (syn_mult π A) (Mult π (Wand A B))" then obtain x y where "Some σ = x ⊕ y" "x, s, Δ ⊨ syn_mult π A" "y, s, Δ ⊨ Mult π (Wand A B)" by auto then have "y, s, Δ ⊨ Wand (syn_mult π A) (syn_mult π B)" by (metis syn_mult.simps(2) syn_sen_mult_same) then show "σ, s, Δ ⊨ syn_mult π B" using ‹Some σ = x ⊕ y› ‹x, s, Δ ⊨ syn_mult π A› ‹y, s, Δ ⊨ Wand (syn_mult π A) (syn_mult π B)› commutative by auto qed theorem package_wand: assumes "Star F (syn_mult π A), Δ ⊢ syn_mult π B" shows "F, Δ ⊢ Mult π (Wand A B)" by (metis adjunct2 assms entails_def syn_mult.simps(2) syn_sen_mult_same) text ‹The following four theorems correspond to the rules shown in Section 5.2 of the paper~\<^cite>‹"UnboundedSL"›.› theorem fold_lfp: assumes "pos_neg_rec_call True A" shows "syn_mult π A, LFP (applies_eq A) ⊢ Mult π Pred" by (simp add: assms entails_def exists_lfp_gfp(1) syn_sen_mult_same) theorem unfold_lfp: assumes "pos_neg_rec_call True A" shows "Mult π Pred, LFP (applies_eq A) ⊢ syn_mult π A" by (simp add: assms entails_def exists_lfp_gfp(1) syn_sen_mult_same) theorem fold_gfp: assumes "pos_neg_rec_call True A" shows "syn_mult π A, GFP (applies_eq A) ⊢ Mult π Pred" by (simp add: assms entails_def exists_lfp_gfp(2) syn_sen_mult_same) theorem unfold_gfp: assumes "pos_neg_rec_call True A" shows "Mult π Pred, GFP (applies_eq A) ⊢ syn_mult π A" by (simp add: assms entails_def exists_lfp_gfp(2) syn_sen_mult_same) text ‹The following theorems correspond to the rule shown in Section 5.3 of the paper~\<^cite>‹"UnboundedSL"›.› theorem wf_assertion_combinable_lfp: assumes "wf_assertion A" and "pos_neg_rec_call True A" shows "sem_combinable (LFP (applies_eq A))" proof - let ?f = "λa b. { σ |σ p q. sadd p q = one ∧ Some σ = p ⊙ a ⊕ q ⊙ b}" have "set_closure_property ?f (LFP (applies_eq A))" proof (rule FP_preserves_set_closure_property(2)) show "monotonic (applies_eq A)" using assms(2) pos_neg_rec_call_mono by blast fix Δ :: "('d, 'c, 'a) interp" assume asm0: "set_closure_property ?f Δ" then have "sem_combinable Δ" by (metis combinable_set_closure) then show "set_closure_property ?f (applies_eq A Δ)" by (metis assms(1) combinable_set_closure sem_combinable_equiv wf_implies_combinable) qed then show ?thesis using combinable_set_closure by metis qed theorem wf_assertion_combinable_gfp: assumes "wf_assertion A" and "pos_neg_rec_call True A" shows "sem_combinable (GFP (applies_eq A))" proof - let ?f = "λa b. { σ |σ p q. sadd p q = one ∧ Some σ = p ⊙ a ⊕ q ⊙ b}" have "set_closure_property ?f (GFP (applies_eq A))" proof (rule FP_preserves_set_closure_property(1)) show "monotonic (applies_eq A)" using assms(2) pos_neg_rec_call_mono by blast fix Δ :: "('d, 'c, 'a) interp" assume asm0: "set_closure_property ?f Δ" then have "sem_combinable Δ" by (metis combinable_set_closure) then show "set_closure_property ?f (applies_eq A Δ)" by (metis assms(1) combinable_set_closure sem_combinable_equiv wf_implies_combinable) qed then show ?thesis using combinable_set_closure by metis qed theorem wf_combine: assumes "wf_assertion A" and "pos_neg_rec_call True A" shows "Star (Mult α Pred) (Mult β Pred), LFP (applies_eq A) ⊢ Mult (sadd α β) Pred" and "Star (Mult α Pred) (Mult β Pred), GFP (applies_eq A) ⊢ Mult (sadd α β) Pred" apply (metis assms(1) assms(2) logic.combinable_def logic.wf_implies_combinable logic_axioms wf_assertion.simps(1) wf_assertion_combinable_lfp) by (metis assms(1) assms(2) logic.combinable_def logic.wf_implies_combinable logic_axioms wf_assertion.simps(1) wf_assertion_combinable_gfp) end end