Theory Symbex_MonadSE
theory Symbex_MonadSE
imports Seq_MonadSE
begin
subsection‹Definition and Properties of Valid Execution Sequences›
text‹A key-notion in our framework is the \emph{valid} execution
sequence, \ie{} a sequence that:
\begin{enumerate}
\item terminates (not obvious since while),
\item results in a final @{term True},
\item does not fail globally (but recall the FailSave and FailPurge
variants of @{term mbind}-operators, that handle local exceptions in
one or another way).
\end{enumerate}
Seen from an automata perspective (where the monad - operations correspond to
the step function), valid execution sequences can be used to model ``feasible paths''
across an automaton.›
definition valid_SE :: "'σ ⇒ (bool,'σ) MON⇩S⇩E ⇒ bool" (infix ‹⊨› 9)
where "(σ ⊨ m) = (m σ ≠ None ∧ fst(the (m σ)))"
text‹This notation consideres failures as valid -- a definition
inspired by I/O conformance.›
subsubsection‹Valid Execution Sequences and their Symbolic Execution›
lemma exec_unit_SE [simp]: "(σ ⊨ (result P)) = (P)"
by(auto simp: valid_SE_def unit_SE_def)
lemma exec_unit_SE' [simp]: "(σ⇩0 ⊨ (λσ. Some (f σ, σ))) = (f σ⇩0)"
by(simp add: valid_SE_def )
lemma exec_fail_SE [simp]: "(σ ⊨ fail⇩S⇩E) = False"
by(auto simp: valid_SE_def fail_SE_def)
lemma exec_fail_SE'[simp]: "¬(σ⇩0 ⊨ (λσ. None))"
by(simp add: valid_SE_def )
text‹The following the rules are in a sense the heart of the entire symbolic execution approach›
lemma exec_bind_SE_failure:
"A σ = None ⟹ ¬(σ ⊨ ((s ← A ; M s)))"
by(simp add: valid_SE_def unit_SE_def bind_SE_def)
lemma exec_bind_SE_failure2:
"A σ = None ⟹ ¬(σ ⊨ ((A ;- M)))"
by(simp add: valid_SE_def unit_SE_def bind_SE_def bind_SE'_def)
lemma exec_bind_SE_success:
"A σ = Some(b,σ') ⟹ (σ ⊨ ((s ← A ; M s))) = (σ' ⊨ (M b))"
by(simp add: valid_SE_def unit_SE_def bind_SE_def )
lemma exec_bind_SE_success2:
"A σ = Some(b,σ') ⟹ (σ ⊨ ((A ;- M))) = (σ' ⊨ M)"
by(simp add: valid_SE_def unit_SE_def bind_SE_def bind_SE'_def )
lemma exec_bind_SE_success':
"M σ = Some(f σ,σ) ⟹ (σ ⊨ M) = f σ"
by(simp add: valid_SE_def unit_SE_def bind_SE_def )
lemma exec_bind_SE_success'':
"σ ⊨ ((s ← A ; M s)) ⟹ ∃ v σ'. the(A σ) = (v,σ') ∧ (σ' ⊨ M v)"
apply(auto simp: valid_SE_def unit_SE_def bind_SE_def)
apply(cases "A σ", simp_all)
apply(drule_tac x="A σ" and f=the in arg_cong, simp)
apply(rule_tac x="fst aa" in exI)
apply(rule_tac x="snd aa" in exI, auto)
done
lemma exec_bind_SE_success''':
"σ ⊨ ((s ← A ; M s)) ⟹ ∃ a. (A σ) = Some a ∧ (snd a ⊨ M (fst a))"
apply(auto simp: valid_SE_def unit_SE_def bind_SE_def)
apply(cases "A σ", simp_all)
apply(drule_tac x="A σ" and f=the in arg_cong, simp)
apply(rule_tac x="fst aa" in exI)
apply(rule_tac x="snd aa" in exI, auto)
done
lemma exec_bind_SE_success'''' :
"σ ⊨ ((s ← A ; M s)) ⟹ ∃ v σ'. A σ = Some(v,σ') ∧ (σ' ⊨ M v)"
apply(auto simp: valid_SE_def unit_SE_def bind_SE_def)
apply(cases "A σ", simp_all)
apply(drule_tac x="A σ" and f=the in arg_cong, simp)
apply(rule_tac x="fst aa" in exI)
apply(rule_tac x="snd aa" in exI, auto)
done
lemma valid_bind_cong : " f σ = g σ ⟹ (σ ⊨ (x ← f ; M x)) = (σ ⊨ (x ← g ; M x))"
unfolding bind_SE'_def bind_SE_def valid_SE_def
by simp
lemma valid_bind'_cong : " f σ = g σ ⟹ (σ ⊨ f ;- M) = (σ ⊨ g ;- M)"
unfolding bind_SE'_def bind_SE_def valid_SE_def
by simp
text‹Recall \verb+mbind_unit+ for the base case.›
lemma valid_mbind_mt : "(σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e [] f; unit⇩S⇩E (P s))) = P [] " by simp
lemma valid_mbind_mtE: "σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e [] f; unit⇩S⇩E (P s)) ⟹ (P [] ⟹ Q) ⟹ Q"
by(auto simp: valid_mbind_mt)
lemma valid_mbind'_mt : "(σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p [] f; unit⇩S⇩E (P s))) = P [] " by simp
lemma valid_mbind'_mtE: "σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p [] f; unit⇩S⇩E (P s)) ⟹ (P [] ⟹ Q) ⟹ Q"
by(auto simp: valid_mbind'_mt)
lemma valid_mbind''_mt : "(σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e [] f; unit⇩S⇩E (P s))) = P [] "
by(simp add: mbind''.simps valid_SE_def bind_SE_def unit_SE_def)
lemma valid_mbind''_mtE: "σ ⊨ ( s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e [] f; unit⇩S⇩E (P s)) ⟹ (P [] ⟹ Q) ⟹ Q"
by(auto simp: valid_mbind''_mt)
lemma exec_mbindFSave_failure:
"ioprog a σ = None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (a#S) ioprog ; M s)) = (σ ⊨ (M []))"
by(simp add: valid_SE_def unit_SE_def bind_SE_def)
lemma exec_mbindFStop_failure:
"ioprog a σ = None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (a#S) ioprog ; M s)) = (False)"
by(simp add: exec_bind_SE_failure)
lemma exec_mbindFPurge_failure:
"ioprog a σ = None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e (a#S) ioprog ; M s)) =
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e (S) ioprog ; M s))"
by(simp add: valid_SE_def unit_SE_def bind_SE_def mbind''.simps)
lemma exec_mbindFSave_success :
"ioprog a σ = Some(b,σ') ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (a#S) ioprog ; M s)) =
(σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S ioprog ; M (b#s)))"
unfolding valid_SE_def unit_SE_def bind_SE_def
by(cases "mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S ioprog σ'", auto)
lemma exec_mbindFStop_success :
"ioprog a σ = Some(b,σ') ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (a#S) ioprog ; M s)) =
(σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S ioprog ; M (b#s)))"
unfolding valid_SE_def unit_SE_def bind_SE_def
by(cases "mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S ioprog σ'", auto simp: mbind'.simps)
lemma exec_mbindFPurge_success :
"ioprog a σ = Some(b,σ') ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e (a#S) ioprog ; M s)) =
(σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e S ioprog ; M (b#s)))"
unfolding valid_SE_def unit_SE_def bind_SE_def
by(cases "mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e S ioprog σ'", auto simp: mbind''.simps)
text‹versions suited for rewriting›
lemma exec_mbindFStop_success':‹ioprog a σ ≠ None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (a#S) ioprog ; M s)) =
((snd o the)(ioprog a σ) ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S ioprog ; M ((fst o the)(ioprog a σ)#s)))›
using exec_mbindFStop_success by fastforce
lemma exec_mbindFSave_success': ‹ioprog a σ ≠ None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (a#S) ioprog ; M s)) =
((snd o the)(ioprog a σ) ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S ioprog ; M ((fst o the)(ioprog a σ)#s)))›
using exec_mbindFSave_success by fastforce
lemma exec_mbindFPurge_success' :
"ioprog a σ ≠ None ⟹
(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e (a#S) ioprog ; M s)) =
((snd o the)(ioprog a σ) ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e S ioprog ; M ((fst o the)(ioprog a σ)#s)))"
using exec_mbindFPurge_success by fastforce
lemma exec_mbindFSave:
"(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (a#S) ioprog ; return (P s))) =
(case ioprog a σ of
None ⇒ (σ ⊨ (return (P [])))
| Some(b,σ') ⇒ (σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S ioprog ; return (P (b#s)))))"
apply(case_tac "ioprog a σ")
apply(auto simp: exec_mbindFSave_failure exec_mbindFSave_success split: prod.splits)
done
lemma mbind_eq_sexec:
assumes * : "⋀b σ'. f a σ = Some(b,σ') ⟹
(os ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S f; P (b#os)) = (os ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S f; P' (b#os))"
shows "( a ← f a; x ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S f; P (a # x)) σ =
( a ← f a; x ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S f; P'(a # x)) σ"
apply(cases "f a σ = None")
apply(subst bind_SE_def, simp)
apply(subst bind_SE_def, simp)
apply auto
apply(subst bind_SE_def, simp)
apply(subst bind_SE_def, simp)
apply(simp add: *)
done
lemma mbind_eq_sexec':
assumes * : "⋀b σ'. f a σ = Some(b,σ') ⟹
(P (b))σ' = (P' (b))σ'"
shows "( a ← f a; P (a)) σ =
( a ← f a; P'(a)) σ"
apply(cases "f a σ = None")
apply(subst bind_SE_def, simp)
apply(subst bind_SE_def, simp)
apply auto
apply(subst bind_SE_def, simp)
apply(subst bind_SE_def, simp)
apply(simp add: *)
done
lemma mbind'_concat:
"(os ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (S@T) f; P os) = (os ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S f; os' ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p T f; P (os @ os'))"
proof (rule ext, rename_tac "σ", induct S arbitrary: σ P)
case Nil show ?case by simp
next
case (Cons a S) show ?case
apply(insert Cons.hyps, simp)
by(rule mbind_eq_sexec',simp)
qed
lemma assert_suffix_inv :
"σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p xs istep; assert⇩S⇩E (P))
⟹ ∀σ. P σ ⟶ (σ ⊨ (_ ← istep x; assert⇩S⇩E (P)))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (xs @ [x]) istep; assert⇩S⇩E (P))"
apply(subst mbind'_concat, simp)
unfolding bind_SE_def assert_SE_def valid_SE_def
apply(auto split: option.split option.split_asm)
apply(case_tac "aa",simp_all)
apply(case_tac "P bb",simp_all)
apply (metis option.distinct(1))
apply(case_tac "aa",simp_all)
apply(case_tac "P bb",simp_all)
by (metis option.distinct(1))
text‹Universal splitting and symbolic execution rule›
lemma exec_mbindFSave_E:
assumes seq : "(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (a#S) ioprog ; (P s)))"
and none: "ioprog a σ = None ⟹ (σ ⊨ (P [])) ⟹ Q"
and some: "⋀ b σ'. ioprog a σ = Some(b,σ') ⟹ (σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S ioprog;(P (b#s)))) ⟹ Q "
shows "Q"
using seq
proof(cases "ioprog a σ")
case None assume ass:"ioprog a σ = None" show "Q"
apply(rule none[OF ass])
apply(insert ass, erule_tac ioprog1=ioprog in exec_mbindFSave_failure[THEN iffD1],rule seq)
done
next
case (Some aa) assume ass:"ioprog a σ = Some aa" show "Q"
apply(insert ass,cases "aa",simp, rename_tac "out" "σ'")
apply(erule some)
apply(insert ass,simp)
apply(erule_tac ioprog1=ioprog in exec_mbindFSave_success[THEN iffD1],rule seq)
done
qed
text‹The next rule reveals the particular interest in deduction;
as an elimination rule, it allows for a linear conversion of a validity judgement
@{term "mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p"} over an input list @{term "S"} into a constraint system; without any
branching ... Symbolic execution can even be stopped tactically whenever
@{term "ioprog a σ = Some(b,σ')"} comes to a contradiction.›
lemma exec_mbindFStop_E:
assumes seq : "(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (a#S) ioprog ; (P s)))"
and some: "⋀b σ'. ioprog a σ = Some(b,σ') ⟹ (σ'⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S ioprog;(P(b#s)))) ⟹ Q"
shows "Q"
using seq
proof(cases "ioprog a σ")
case None assume ass:"ioprog a σ = None" show "Q"
apply(insert ass seq)
apply(drule_tac σ=σ and S=S and M=P in exec_mbindFStop_failure, simp)
done
next
case (Some aa) assume ass:"ioprog a σ = Some aa" show "Q"
apply(insert ass,cases "aa",simp, rename_tac "out" "σ'")
apply(erule some)
apply(insert ass,simp)
apply(erule_tac ioprog1=ioprog in exec_mbindFStop_success[THEN iffD1],rule seq)
done
qed
lemma exec_mbindFPurge_E:
assumes seq : "(σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e (a#S) ioprog ; (P s)))"
and none: "ioprog a σ = None ⟹ (σ ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e S ioprog;(P (s)))) ⟹ Q"
and some: "⋀ b σ'. ioprog a σ = Some(b,σ') ⟹ (σ' ⊨ (s ← mbind⇩F⇩a⇩i⇩l⇩P⇩u⇩r⇩g⇩e S ioprog;(P (b#s)))) ⟹ Q "
shows "Q"
using seq
proof(cases "ioprog a σ")
case None assume ass:"ioprog a σ = None" show "Q"
apply(rule none[OF ass])
apply(insert ass, erule_tac ioprog1=ioprog in exec_mbindFPurge_failure[THEN iffD1],rule seq)
done
next
case (Some aa) assume ass:"ioprog a σ = Some aa" show "Q"
apply(insert ass,cases "aa",simp, rename_tac "out" "σ'")
apply(erule some)
apply(insert ass,simp)
apply(erule_tac ioprog1=ioprog in exec_mbindFPurge_success[THEN iffD1],rule seq)
done
qed
lemma assert_disch1 :" P σ ⟹ (σ ⊨ (x ← assert⇩S⇩E P; M x)) = (σ ⊨ (M True))"
by(auto simp: bind_SE_def assert_SE_def valid_SE_def)
lemma assert_disch2 :" ¬ P σ ⟹ ¬ (σ ⊨ (x ← assert⇩S⇩E P ; M s))"
by(auto simp: bind_SE_def assert_SE_def valid_SE_def)
lemma assert_disch3 :" ¬ P σ ⟹ ¬ (σ ⊨ (assert⇩S⇩E P))"
by(auto simp: bind_SE_def assert_SE_def valid_SE_def)
lemma assert_disch4 :" P σ ⟹ (σ ⊨ (assert⇩S⇩E P))"
by(auto simp: bind_SE_def assert_SE_def valid_SE_def)
lemma assert_simp : "(σ ⊨ assert⇩S⇩E P) = P σ"
by (meson assert_disch3 assert_disch4)
lemmas assert_D = assert_simp[THEN iffD1]
lemma assert_bind_simp : "(σ ⊨ (x ← assert⇩S⇩E P; M x)) = (P σ ∧ (σ ⊨ (M True)))"
by(auto simp: bind_SE_def assert_SE_def valid_SE_def split: HOL.if_split_asm)
lemmas assert_bindD = assert_bind_simp[THEN iffD1]
lemma assume_D : "(σ ⊨ (_ ← assume⇩S⇩E P; M)) ⟹ ∃ σ. (P σ ∧ (σ ⊨ M) )"
apply(auto simp: bind_SE_def assume_SE_def valid_SE_def split: HOL.if_split_asm)
apply(rule_tac x="Eps P" in exI, auto)
apply(subst Hilbert_Choice.someI,assumption,simp)
done
lemma assume_E :
assumes * : "σ ⊨ ( _ ← assume⇩S⇩E P; M) "
and ** : "⋀ σ. P σ ⟹ σ ⊨ M ⟹ Q"
shows "Q"
apply(insert *)
by(insert *[THEN assume_D], auto intro: **)
lemma assume_E' :
assumes * : "σ ⊨ assume⇩S⇩E P ;- M"
and ** : "⋀ σ. P σ ⟹ σ ⊨ M ⟹ Q"
shows "Q"
by(insert *[simplified "bind_SE'_def", THEN assume_D], auto intro: **)
text‹These two rule prove that the SE Monad in connection with the notion of valid sequence
is actually sufficient for a representation of a Boogie-like language. The SBE monad with explicit
sets of states --- to be shown below --- is strictly speaking not necessary (and will therefore
be discontinued in the development).›
term "if⇩S⇩E P then B⇩1 else B⇩2 fi"
lemma if_SE_D1 : "P σ ⟹ (σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi)) = (σ ⊨ B⇩1)"
by(auto simp: if_SE_def valid_SE_def)
lemma if_SE_D1' : "P σ ⟹ (σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi);-M) = (σ ⊨ (B⇩1;-M))"
by(auto simp: if_SE_def valid_SE_def bind_SE'_def bind_SE_def)
lemma if_SE_D2 : "¬ P σ ⟹ (σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi)) = (σ ⊨ B⇩2)"
by(auto simp: if_SE_def valid_SE_def)
lemma if_SE_D2' : "¬ P σ ⟹ (σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi);-M) = (σ ⊨ B⇩2;-M)"
by(auto simp: if_SE_def valid_SE_def bind_SE'_def bind_SE_def)
lemma if_SE_split_asm :
"(σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi)) = ((P σ ∧ (σ ⊨ B⇩1)) ∨ (¬ P σ ∧ (σ ⊨ B⇩2)))"
by(cases "P σ",auto simp: if_SE_D1 if_SE_D2)
lemma if_SE_split_asm':
"(σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi);-M) = ((P σ ∧ (σ ⊨ B⇩1;-M)) ∨ (¬ P σ ∧ (σ ⊨ B⇩2;-M)))"
by(cases "P σ",auto simp: if_SE_D1' if_SE_D2')
lemma if_SE_split:
"(σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi)) = ((P σ ⟶ (σ ⊨ B⇩1)) ∧ (¬ P σ ⟶ (σ ⊨ B⇩2)))"
by(cases "P σ", auto simp: if_SE_D1 if_SE_D2)
lemma if_SE_split':
"(σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi);-M) = ((P σ ⟶ (σ ⊨ B⇩1;-M)) ∧ (¬ P σ ⟶ (σ ⊨ B⇩2;-M)))"
by(cases "P σ", auto simp: if_SE_D1' if_SE_D2')
lemma if_SE_execE:
assumes A: "σ ⊨ ((if⇩S⇩E P then B⇩1 else B⇩2 fi))"
and B: "P σ ⟹ σ ⊨ (B⇩1) ⟹ Q"
and C: "¬ P σ⟹ σ ⊨ (B⇩2) ⟹ Q"
shows "Q"
by(insert A [simplified if_SE_split],cases "P σ", simp_all, auto elim: B C)
lemma if_SE_execE':
assumes A: "σ ⊨ ((if⇩S⇩E P then B⇩1 else B⇩2 fi);-M)"
and B: "P σ ⟹ σ ⊨ (B⇩1;-M) ⟹ Q"
and C: "¬ P σ⟹ σ ⊨ (B⇩2;-M) ⟹ Q"
shows "Q"
by(insert A [simplified if_SE_split'],cases "P σ", simp_all, auto elim: B C)
lemma exec_while :
"(σ ⊨ ((while⇩S⇩E b do c od) ;- M)) =
(σ ⊨ ((if⇩S⇩E b then c ;- (while⇩S⇩E b do c od) else unit⇩S⇩E ()fi) ;- M))"
apply(subst while_SE_unfold)
by(simp add: bind_SE'_def )
lemmas exec_whileD = exec_while[THEN iffD1]
lemma if_SE_execE'':
"σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi) ;- M
⟹ (P σ ⟹ σ ⊨ B⇩1 ;- M ⟹ Q)
⟹ (¬ P σ ⟹ σ ⊨ B⇩2 ;- M ⟹ Q)
⟹ Q"
by(auto elim: if_SE_execE')
definition "opaque (x::bool) = x"
lemma if_SE_execE''_pos:
"σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi) ;- M
⟹ (P σ ⟹ σ ⊨ B⇩1 ;- M ⟹ Q)
⟹ (opaque (σ ⊨ (if⇩S⇩E P then B⇩1 else B⇩2 fi) ;- M) ⟹ Q)
⟹ Q"
using opaque_def by auto
lemma [code]:
"(σ ⊨ m) = (case (m σ) of None ⇒ False | (Some (x,y)) ⇒ x)"
apply(simp add: valid_SE_def)
apply(cases "m σ = None", simp_all)
apply(insert not_None_eq, auto)
done
lemma "P σ ⊨ (_ ← assume⇩S⇩E P ; x ← M; assert⇩S⇩E (λσ. (x=X) ∧ Q x σ))"
oops
lemma "∀σ. ∃ X. σ ⊨ (_ ← assume⇩S⇩E P ; x ← M; assert⇩S⇩E (λσ. x=X ∧ Q x σ))"
oops
lemma monadic_sequence_rule:
"⋀ X σ⇩1. (σ ⊨ (_ ← assume⇩S⇩E (λσ'. (σ=σ') ∧ P σ) ; x ← M;
assert⇩S⇩E (λσ. (x=X) ∧ (σ=σ⇩1) ∧ Q x σ)))
∧
(σ⇩1 ⊨ (_ ← assume⇩S⇩E (λσ. (σ=σ⇩1) ∧ Q x σ) ;
y ← M'; assert⇩S⇩E (λσ. R x y σ)))
⟹
σ ⊨ (_ ← assume⇩S⇩E (λσ'. (σ=σ') ∧ P σ) ; x ← M; y ← M'; assert⇩S⇩E (R x y))"
apply(elim exE impE conjE)
apply(drule assume_D)
apply(elim exE impE conjE)
unfolding valid_SE_def assume_SE_def assert_SE_def bind_SE_def
apply(auto split: if_split HOL.if_split_asm Option.option.split Option.option.split_asm)
apply (metis (mono_tags, lifting) option.simps(3) someI_ex)
oops
lemma "∃ X. σ ⊨ (_ ← assume⇩S⇩E P ; x ← M; assert⇩S⇩E (λσ. x=X ∧ Q x σ))
⟹
σ ⊨ (_ ← assume⇩S⇩E P ; x ← M; assert⇩S⇩E (λσ. Q x σ))"
unfolding valid_SE_def assume_SE_def assert_SE_def bind_SE_def
by(auto split: if_split HOL.if_split_asm Option.option.split Option.option.split_asm)
lemma exec_skip:
"(σ ⊨ skip⇩S⇩E ;- M) = (σ ⊨ M)"
by (simp add: skip⇩S⇩E_def)
lemmas exec_skipD = exec_skip[THEN iffD1]
text‹Test-Refinements will be stated in terms of the failsave @{term mbind}, opting
more generality. The following lemma allows for an optimization both in
test execution as well as in symbolic execution for an important special case of
the post-codition: Whenever the latter has the constraint that the length of input and
output sequence equal each other (that is to say: no failure occured), failsave mbind
can be reduced to failstop mbind ...›
lemma mbindFSave_vs_mbindFStop :
"(σ ⊨ (os ← (mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e ιs ioprog); result(length ιs = length os ∧ P ιs os))) =
(σ ⊨ (os ← (mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ιs ioprog); result(P ιs os)))"
apply(rule_tac x=P in spec)
apply(rule_tac x=σ in spec)
proof(induct "ιs")
case Nil show ?case by(simp_all add: mbind_try try_SE_def del: Seq_MonadSE.mbind.simps)
case (Cons a ιs) show ?case
apply(rule allI, rename_tac "σ",rule allI, rename_tac "P")
apply(insert Cons.hyps)
apply(case_tac "ioprog a σ")
apply(simp only: exec_mbindFSave_failure exec_mbindFStop_failure, simp)
apply(simp add: split_paired_all del: Seq_MonadSE.mbind.simps )
apply(rename_tac "σ'")
apply(subst exec_mbindFSave_success, assumption)
apply(subst (2) exec_bind_SE_success, assumption)
apply(erule_tac x="σ'" in allE)
apply(erule_tac x="λιs s. P (a # ιs) (aa # s)" in allE)
apply(simp)
done
qed
lemma mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e_vs_mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p:
assumes A: "∀ ι∈set ιs. ∀ σ. ioprog ι σ ≠ None"
shows "(σ ⊨ (os ← (mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e ιs ioprog); P os)) =
(σ ⊨ (os ← (mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ιs ioprog); P os))"
proof(insert A, erule rev_mp, induct "ιs")
case Nil show ?case by simp
next
case (Cons a ιs)
from Cons.hyps
have B:"∀ S f σ. mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e S f σ ≠ None " by simp
have C:"(∀ ι∈set ιs. ∀ σ. ioprog ι σ ≠ None)
⟶ (∀σ. mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ιs ioprog σ = mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e ιs ioprog σ)"
apply(induct ιs, simp)
apply(intro impI allI,rename_tac "σ")
apply(simp add: Seq_MonadSE.mbind'.simps(2))
apply(insert A, erule_tac x="a" in ballE)
apply(erule_tac x="σ" and P="λσ . ioprog a σ ≠ None" in allE)
apply(auto split:option.split)
done
show ?case by (meson C exec_mbindFSave_success' exec_mbindFStop_success'
list.set_intros(1) list.set_intros(2) valid_bind_cong)
qed
text‹Symbolic execution rules for assertions.›
lemma assert_suffix_seq :
"σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p xs iostep; assert⇩S⇩E (P))
⟹ ∀σ. P σ ⟶ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ys iostep; assert⇩S⇩E (Q)))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (xs @ ys) iostep; assert⇩S⇩E (Q))"
apply(subst mbind'_concat)
unfolding bind_SE_def assert_SE_def valid_SE_def
apply(auto split: option.split option.split_asm, rename_tac "aa" "ba" "ab" "bb" )
apply (metis option.distinct(1))
by (meson option.distinct(1))
lemma assert_suffix_seq2 :
"σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p xs iostep; assert⇩S⇩E (P))
⟹ (⋀ σ. P σ ⟹ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ys iostep; assert⇩S⇩E (Q))))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (xs @ ys) iostep; assert⇩S⇩E (Q))"
by (simp add: assert_suffix_seq)
lemma assert_suffix_seq_map :
"σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (map f xs) iostep; assert⇩S⇩E (P))
⟹ (⋀ σ. P σ ⟹ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (map f ys) iostep; assert⇩S⇩E (Q))))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (map f (xs @ ys)) iostep; assert⇩S⇩E (Q))"
by (simp add: assert_suffix_seq)
lemma assert_suffix_seq_tot :
"∀x σ. iostep x σ ≠ None
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e xs iostep; assert⇩S⇩E (P))
⟹ ∀σ. P σ ⟶ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ys iostep; assert⇩S⇩E (Q)))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (xs @ ys) iostep; assert⇩S⇩E (Q))"
apply(subst Symbex_MonadSE.mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e_vs_mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p, simp)
apply(subst (asm) Symbex_MonadSE.mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e_vs_mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p, simp)
by (simp add: assert_suffix_seq)
lemma assert_suffix_seq_tot2 :
"(⋀ x σ. iostep x σ ≠ None)
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e xs iostep; assert⇩S⇩E (P))
⟹ (⋀σ. P σ ⟹ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p ys iostep; assert⇩S⇩E (Q))))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (xs @ ys) iostep; assert⇩S⇩E (Q))"
by (simp add: assert_suffix_seq_tot)
lemma assert_suffix_seq_tot3 :
"(⋀ x σ. iostep x σ ≠ None)
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (map f xs) iostep; assert⇩S⇩E (P))
⟹ (⋀σ. P σ ⟹ (σ ⊨ (_ ← mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p (map f ys) iostep; assert⇩S⇩E (Q))))
⟹ σ ⊨ ( _ ← mbind⇩F⇩a⇩i⇩l⇩S⇩a⇩v⇩e (map f (xs @ ys)) iostep; assert⇩S⇩E (Q))"
by (simp add: assert_suffix_seq_tot)
lemma assert_disch :
"(σ ⊨ (_ ← iostep x; assert⇩S⇩E (Q))) =
(case iostep x σ of None ⇒ False | Some(_,σ') ⇒ Q σ')"
by (smt (verit, best) assert_simp bind_SE_def option.case_eq_if split_def valid_SE_def)
lemma assert_disch_tot :
"∀x σ. iostep x σ ≠ None ⟹ (σ ⊨ (_ ← iostep x; assert⇩S⇩E (Q))) = (Q (snd(the(iostep x σ))))"
apply(subst assert_disch)
by (metis option.case_eq_if split_beta')
lemma assert_disch_tot2 :
"(⋀x σ. iostep x σ ≠ None) ⟹ (σ ⊨ (_ ← iostep x; assert⇩S⇩E (Q))) = (Q (snd(the(iostep x σ))))"
apply(subst assert_disch)
by (metis option.case_eq_if split_beta')
lemma mbind_total_if_step_total :
"(⋀x σ. x ∈ set S ⟹ iostep x σ ≠ None) ⟹ (⋀σ. mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S iostep σ ≠ None)"
proof(induct S)
case Nil
then show ?case by (simp add: unit_SE_def)
next
case (Cons a S σ)
have 1 : "∀ x σ. x ∈ set S ⟶ iostep x σ ≠ None"
by (simp add: Cons.prems)
have 2 : "⋀σ. mbind⇩F⇩a⇩i⇩l⇩S⇩t⇩o⇩p S iostep σ ≠ None"
using Cons.hyps Cons.prems by fastforce
then show ?case
apply(simp add : mbind'.simps(2) 1 2)
by (simp add: "2" Cons.prems option.case_eq_if split_beta')
qed
subsection‹Miscellaneous›
no_notation unit_SE (‹(result _)› 8)
end