(* Tested with Isabelle2023, 15-Feb-2024 *) theory Correctness_Incorrectness imports Main begin typedecl var type_synonym state = "var \ int" type_synonym assertion = "state set" type_synonym command = "(state \ state) set" definition skip where [simp]: "skip \ { (\,\') | \ \'. \ = \' }" definition diverge :: "command" where "diverge \ {}" definition FALSE :: "assertion" where "FALSE \ {}" fun NOT :: "assertion \ assertion" where "NOT P = {\. \ \ P}" definition TRUE :: "assertion" where [simp]: "TRUE \ UNIV" fun determ :: "command \ state set" where "determ c = {\. \\1 \2. (\, \1) \ c \ (\, \2) \ c \ \1 = \2}" fun diverges :: "command \ state set" where "diverges c = {\. \\'. (\, \') \ c}" (* The set of all states that c can reach if it starts executing in a P state. *) (* Same as strongest post *) fun may_reach :: "(assertion \ command) \ assertion" where "may_reach (P, c) = {\'. \\. (\,\') \ c \ \ \ P}" (* The set of all states from which c is guaranteed only to reach Q states (if it reaches any final state at all). *) (* Same as weakest pre *) fun must_reach :: "(command \ assertion) \ assertion" where "must_reach (c, Q) = {\. \\'. (\,\') \ c \ \' \ Q}" lemma "may_reach (P, c) = NOT (must_reach (c^-1, NOT P))" by simp (* weakest liberal pre *) (* The set of all states from which c can only reach Q states. *) fun wlp :: "(command \ assertion) \ assertion" where "wlp (c, Q) = {\. \\'. (\,\') \ c \ \' \ Q}" (* weakest pre *) fun wp :: "(command \ assertion) \ assertion" where "wp (c, Q) = {\. (\\'. (\,\') \ c) \ (\\'. (\,\') \ c \ \' \ Q)}" lemma "wp (c, Q) \ wlp (c, Q)" by auto lemma "diverges c = {} \ wlp (c, Q) \ wp (c, Q)" by auto (* weakest possible pre *) (* The set of all states from which c can reach Q states. *) (* Note that Zhang and Kaminsky OOPSLA 2022 call this "weakest precondition" *) fun wpp :: "(command \ assertion) \ assertion" where "wpp (c, Q) = {\. \\' \ Q. (\,\') \ c}" lemma "\ diverges c = {}; determ c = TRUE \ \ wpp (c, Q) = wlp (c, Q)" by fastforce lemma "\ determ c = TRUE \ \ wpp (c, Q) \ wlp (c, Q)" by fastforce lemma "\ diverges c = {} \ \ wlp (c, Q) \ wpp (c, Q)" by fastforce lemma "determ c = TRUE \ wpp (c, Q) = wp (c, Q)" by fastforce lemma "determ c = TRUE \ wpp (c, Q) \ wp (c, Q)" by fastforce lemma "wp (c, Q) \ wpp (c, Q)" by fastforce (* strongest post *) (* The set of all states that c can reach if it starts executing in a P state. *) fun sp :: "(assertion \ command) \ assertion" where "sp (P, c) = {\'. \\. (\,\') \ c \ \ \ P}" (* strongest liberal post *) (* The set of all states that c can only reach if it starts executing in a P state. *) fun slp :: "(assertion \ command) \ assertion" where "slp (P, c) = {\'. \\. (\,\') \ c \ \ \ P}" lemma "wpp (c, Q) = may_reach (Q, c^-1)" by auto lemma "may_reach (P, c) = NOT (wlp (c^-1, NOT P))" by simp lemma "wpp (c, Q) = NOT (wlp (c, NOT Q))" by auto lemma "wpp (c, Q) = sp (Q, c^-1)" by auto lemma "must_reach (c, Q) = wlp (c, Q)" by simp lemma "may_reach (P, c) = sp (P, c)" by simp lemma "slp (P, c) = NOT (sp (NOT P, c))" by simp lemma "slp (P, c) = must_reach (c^-1, P)" by simp lemma "slp (P, c) = wlp (c^-1, P)" by simp lemma "P \ diverges c \ sp (P, c) = {}" by auto (* Galois connections observed by Zhang and Kaminski OOPSLA 2022 *) lemma "(P \ wlp (c, Q)) \ (sp (P, c) \ Q)" by auto lemma "(P \ slp (Q, c)) \ (wpp (c, P) \ Q)" by auto (* Partial correctness *) fun pc :: "(assertion \ command \ assertion) \ bool" where (* If command c is executed from a state that satisfies the precondition P, then any state it reaches satisfies the postcondition Q. *) (* "P is sufficient for ensuring that c either reaches Q or diverges." *) (* If P holds, c can only reach states where Q holds. *) "pc (P, c, Q) = (\\ \'. \ \ P \ (\,\') \ c \ \' \ Q)" (* Incorrectness logic *) fun il :: "(assertion \ command \ assertion) \ bool" where (* "Every state that satisfies the postcondition Q can be reached by executing command c from a state that satisfies the precondition P." *) "il (P, c, Q) = (\\'\ Q. \\ \ P. (\, \') \ c)" (* "Sufficient incorrectness logic" *) (* AKA backwards underapproximate Hoare logic *) (* AKA Lisbon triples *) fun sil :: "(assertion \ command \ assertion) \ bool" where "sil (P, c, Q) = (\\ \ P. \\' \ Q. (\, \') \ c)" (* "New triple" *) fun nt :: "(assertion \ command \ assertion) \ bool" where (* "Every state from which c always reaches a state that satisfies Q, must satisfy P." *) (* "If executing c from state \ can only reach states that satisfy Q, then \ must satisfy P."*) (* "P contains all states from which command c can only reach states that satisfy Q." *) (* "If a state forces c to reach Q or diverge, then P must hold." *) (* "P is necessary for ensuring that c either reaches Q or diverges." *) (* If P _doesn't_ hold, c can reach a state where Q _doesn't_ hold. *) "nt (P, c, Q) = (\\. (\\'. (\, \') \ c \ \' \ Q) \ \ \ P)" (* si and nt have equivalent power *) theorem "sil (P, c, Q) \ nt (NOT P, c, NOT Q)" by auto (* Necessary conditions logic *) (* As formalised by Ascari et al in their SIL paper *) fun nc :: "(assertion \ command \ assertion) \ bool" where "nc (P, c, Q) = (\\. (\\'. (\, \') \ c \ \' \ Q) \ \ \ P)" (* ht and nc have equivalent power *) theorem "pc (P, c, Q) \ nc (NOT P, c, NOT Q)" by auto theorem "pc (P, c, Q) \ nc (Q, c^-1, P)" by auto (* Yet another kind of triple *) fun yt :: "(assertion \ command \ assertion) \ bool" where "yt (P, c, Q) = (\\'. (\\. (\, \') \ c \ \ \ P) \ \' \ Q)" (* yt and it have equivalent power *) theorem "yt (P, c, Q) \ il (NOT P, c, NOT Q)" by auto (* may = what may happen if execution starts (or ends) in a particular state *) (* must = what must happen if execution starts (or ends) in a particular state *) (* forward = considering the executions of a command from a particular start state *) (* backward = considering the executions of a command that end in a particular final state *) (* over = if we add behaviours to c, the triple remains valid *) (* under = if we remove behaviours from c, the triple remains valid *) lemma "pc (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, over) *) lemma "il (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, under) *) lemma "nc (P, c, Q) \ (wpp(c, Q) \ P)" by auto (* (may, backward, over) *) lemma "sil (P, c, Q) \ (wpp(c, Q) \ P)" by auto (* (may, backward, under) *) lemma "nc (P, c, Q) \ (Q \ slp(P, c))" by auto (* (must, forward, over) *) lemma "yt (P, c, Q) \ (Q \ slp(P, c))" by auto (* (must, forward, under) *) lemma "pc (P, c, Q) \ (P \ wlp(c, Q))" by auto (* (must, backward, over) *) lemma "nt (P, c, Q) \ (P \ wlp(c, Q))" by auto (* (must, backward, under) *) lemma "pc (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, over) *) lemma "il (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, under) *) lemma "nc (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, over) *) lemma "sil (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, under) *) lemma "nc (P, c, Q) \ (Q \ slp(P, c))" by auto (* (must, forward, over) *) lemma "yt (P, c, Q) \ (Q \ slp(P, c))" by auto (* (must, forward, under) *) lemma "pc (P, c, Q) \ (P \ slp(Q, c\))" by auto (* (must, backward, over) *) lemma "nt (P, c, Q) \ (P \ slp(Q, c\))" by auto (* (must, backward, under) *) lemma "pc (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, over) *) lemma "il (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, under) *) lemma "nc (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, over) *) lemma "sil (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, under) *) lemma "nc (P, c, Q) \ (sp(NOT P, c) \ NOT Q)" by auto (* (must, forward, over) *) lemma "yt (P, c, Q) \ (sp(NOT P, c) \ NOT Q)" by auto (* (must, forward, under) *) lemma "pc (P, c, Q) \ (sp(NOT Q, c\) \ NOT P)" by auto (* (must, backward, over) *) lemma "nt (P, c, Q) \ (sp(NOT Q, c\) \ NOT P)" by auto (* (must, backward, under) *) lemma "il (P, c, Q) \ sil (Q, c\, P)" by auto lemma "pc (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, over) *) lemma "il (P, c, Q) \ (sp(P, c) \ Q)" by auto (* (may, forward, under) *) lemma "nc (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, over) *) lemma "sil (P, c, Q) \ (sp(Q, c\) \ P)" by auto (* (may, backward, under) *) lemma "nc (P, c, Q) \ (Q \ wlp(c\, P))" by auto (* (must, forward, over) *) lemma "yt (P, c, Q) \ (Q \ wlp(c\, P))" by auto (* (must, forward, under) *) lemma "pc (P, c, Q) \ (P \ wlp(c, Q))" by auto (* (must, backward, over) *) lemma "nt (P, c, Q) \ (P \ wlp(c, Q))" by auto (* (must, backward, under) *) lemma "c' \ c \ pc (P, c, Q) \ pc (P, c', Q)" by fastforce (* over *) lemma "c \ c' \ il (P, c, Q) \ il (P, c', Q)" by fastforce (* under *) lemma "c' \ c \ nc (P, c, Q) \ nc (P, c', Q)" by fastforce (* over *) lemma "c \ c' \ sil (P, c, Q) \ sil (P, c', Q)" by fastforce (* under *) lemma "c \ c' \ yt (P, c, Q) \ yt (P, c', Q)" by fastforce (* under *) lemma "c \ c' \ nt (P, c, Q) \ nt (P, c', Q)" by fastforce (* under *) lemma "pc (P, c, Q) \ (wpp(c\, P) \ Q)" by auto (* (may, forward, over) *) lemma "il (P, c, Q) \ (wpp(c\, P) \ Q)" by auto (* (may, forward, under) *) lemma "sil (P, c, Q) \ (P \ sp(Q, c\))" by auto (* (may, backward, over) *) lemma "nc (P, c, Q) \ (P \ sp(Q, c\))" by auto (* (may, backward, under) *) lemma "yt (P, c, Q) \ (wlp(c\, P) \ Q)" by auto (* (must, forward, over) *) lemma "nc (P, c, Q) \ (wlp(c\, P) \ Q)" by auto (* (must, forward, under) *) lemma "pc (P, c, Q) \ (P \ slp(Q, c\))" by auto (* (must, backward, over) *) lemma "nt (P, c, Q) \ (P \ slp(Q, c\))" by auto (* (must, backward, under) *) (* So, there are just 3 interesting semantics for these triples. 1. The original Hoare partial correctness interpretation. 2. Incorrectness triples. 3. Sufficient incorrectness triples. *) (* Formulations of partial correctness *) lemma "pc (P, c, Q) \ (wpp(c\, P) \ Q)" by auto lemma "pc (P, c, Q) \ (P \ slp(Q, c\))" by auto lemma "pc (P, c, Q) \ (P \ wlp(c, Q))" by auto lemma "pc (P, c, Q) \ (sp(P, c) \ Q)" by auto (* And these have equivalent "power" *) lemma "pc (NOT P, c, NOT Q) \ (Q \ slp(P, c))" by auto lemma "pc (NOT P, c, NOT Q) \ (Q \ wlp(c\, P))" by auto lemma "pc (NOT P, c, NOT Q) \ (wpp(c, Q) \ P)" by auto lemma "pc (NOT P, c, NOT Q) \ (sp(Q, c\) \ P)" by auto (* Formulations of incorrectness logic *) lemma "il (P, c, Q) \ (wpp(c\, P) \ Q)" by auto lemma "il (P, c, Q) \ (sp(P, c) \ Q)" by auto (* And these have equivalent "power" *) lemma "il (NOT P, c, NOT Q) \ (Q \ wlp(c\, P))" by auto lemma "il (NOT P, c, NOT Q) \ (Q \ slp(P, c))" by auto (* Formulations of sufficient incorrectness logic *) lemma "sil (P, c, Q) \ (P \ sp(Q, c\))" by auto lemma "sil (P, c, Q) \ (wpp(c, Q) \ P)" by auto (* And these have equivalent "power" *) lemma "sil (NOT P, c, NOT Q) \ (P \ slp(Q, c\))" by auto lemma "sil (NOT P, c, NOT Q) \ (P \ wlp(c, Q))" by auto text \ What happens when command does nothing \ theorem "pc (P, skip, Q) \ P \ Q" by auto theorem "il (P, skip, Q) \ Q \ P" by auto theorem "nt (P, skip, Q) \ Q \ P" by auto theorem "sil (P, skip, Q) \ P \ Q" by auto text \ What happens when command diverges? \ theorem "pc (P, diverge, Q) \ True" by (simp add: diverge_def) theorem "il (P, diverge, Q) \ Q = FALSE" by (simp add: diverge_def FALSE_def) theorem "nt (P, diverge, Q) \ P = TRUE" by (auto simp add: diverge_def) theorem "sil (P, diverge, Q) \ P = FALSE" by (simp add: diverge_def FALSE_def) text \ What happens when precondition is unsatisfiable \ theorem "pc (FALSE, c, Q) \ True" by (simp add: FALSE_def) theorem "il (FALSE, c, Q) \ Q = FALSE" by (simp add: FALSE_def) theorem "nt (FALSE, c, Q) \ (may_reach (NOT Q, c) = TRUE)" oops (* nt(FALSE, c, Q) says no matter what state c is executed from, it can always reach a state that violates Q. *) theorem "sil (FALSE, c, Q) \ True" by (simp add: FALSE_def) text \ What happens when precondition is a tautology? \ theorem "pc (TRUE, c, Q) \ (\\ \'. (\, \') \ c \ \' \ Q)" by simp (* ht(TRUE, c, Q) says no matter what state c is executed from, every state it reaches satisfies Q. *) theorem "il (TRUE, c, Q) \ (\\' \ Q. \\. (\, \') \ c)" by auto (* it(TRUE, c, Q) says that every state that satisfies Q can be reached by executing c. *) theorem "nt (TRUE, c, Q) \ True" by auto theorem "sil (TRUE, c, Q) \ (may_reach (Q, c) = TRUE)" oops text \ What happens when postcondition is unsatisfiable \ theorem "pc (P, c, FALSE) \ P \ diverges c" by (auto simp add: FALSE_def) (* ht(P, c, FALSE) holds iff P is a sufficient condition for c diverging. *) theorem "il (P, c, FALSE) \ True" by (simp add: FALSE_def) theorem "nt (P, c, FALSE) \ diverges c \ P" by (auto simp add: FALSE_def) (* ht(P, c, FALSE) holds iff P is a necessary condition for c diverging. *) theorem "sil (P, c, FALSE) \ P = FALSE" by (auto simp add: FALSE_def) text \ What happens when postcondition is a tautology? \ theorem "pc (P, c, TRUE) \ True" by auto theorem "il (P, c, TRUE) \ (\\'. \\ \ P. (\, \') \ c)" by auto (* it (P, c, TRUE) holds iff every state can be reached by running c on a state that satisfies P, *) theorem "nt (P, c, TRUE) \ P = TRUE" by auto theorem "sil (P, c, TRUE) \ diverges c \ NOT P" by auto text \ Law of consequence \ theorem "\ pc (P, c, Q); P' \ P; Q \ Q' \ \ pc (P', c, Q')" by force theorem "\ il (P, c, Q); P \ P'; Q' \ Q \ \ il (P', c, Q')" by force theorem "\ nt (P, c, Q); P \ P'; Q' \ Q \ \ nt (P', c, Q)" by force theorem "\ sil (P, c, Q); P' \ P; Q \ Q' \ \ sil (P', c, Q')" by force text \ Sequencing of commands \ theorem "\ pc (P, c1, Q); pc (Q, c2, R) \ \ pc (P, c1 O c2, R)" by fastforce theorem "\ il (P, c1, Q); il (Q, c2, R) \ \ il (P, c1 O c2, R)" by fastforce theorem "\ nt (P, c1, Q); nt (Q, c2, R) \ \ nt (P, c1 O c2, R)" by fastforce theorem "\ sil (P, c1, Q); sil (Q, c2, R) \ \ sil (P, c1 O c2, R)" by fastforce text \ Union of commands \ theorem "\ pc (P1, c1, Q1); pc (P2, c2, Q2) \ \ pc (P1 \ P2, c1 \ c2, Q1 \ Q2)" by fastforce theorem "\ il (P1, c1, Q1); il (P2, c2, Q2) \ \ il (P1 \ P2, c1 \ c2, Q1 \ Q2)" by fastforce theorem "\ nt (P1, c1, Q1); nt (P2, c2, Q2) \ \ nt (P1 \ P2, c1 \ c2, Q1 \ Q2)" by fastforce theorem "\ sil (P1, c1, Q1); sil (P2, c2, Q2) \ \ sil (P1 \ P2, c1 \ c2, Q1 \ Q2)" by fastforce text \ Disjunction / conjunction \ theorem "\ pc (P1, c, Q1); pc (P2, c, Q2) \ \ pc (P1 \ P2, c, Q1 \ Q2)" by fastforce theorem "\ pc (P1, c, Q1); pc (P2, c, Q2) \ \ pc (P1 \ P2, c, Q1 \ Q2)" by fastforce theorem "\ il (P1, c, Q1); il (P2, c, Q2) \ \ il (P1 \ P2, c, Q1 \ Q2)" by fastforce theorem "\ nt (P1, c, Q1); nt (P2, c, Q2) \ \ nt (P1 \ P2, c, Q1 \ Q2)" by fastforce theorem "\ sil (P1, c, Q1); sil (P2, c, Q2) \ \ sil (P1 \ P2, c, Q1 \ Q2)" by fastforce text \ Iteration \ theorem il_iter0: "il (P, c\<^sup>*, P)" by auto theorem "nt (P, c\<^sup>*, P)" by auto theorem "sil (P, c\<^sup>*, P)" by auto theorem "pc (P, c, P) \ pc (P, c\<^sup>*, P)" apply (subgoal_tac "\k. pc (P, c^^k, P)") apply (metis rtrancl_power pc.simps) apply (rule nat.induct) apply simp apply (meson pc.simps relpow_Suc_E) done text \ Comparing pc and it \ theorem "\ P \ determ c; P \ diverges c = {} \ \ pc (P, c, Q) \ il (Q, c\, P)" by force theorem "\ P \ diverges c = {} \ \ pc (P, c, Q) \ il (Q, c\, P)" by force theorem "\ P \ determ c \ \ il (Q, c\, P) \ pc (P, c, Q)" by force text \ Comparing ht and si \ theorem "\ P \ determ c; P \ diverges c = {} \ \ pc(P, c, Q) \ sil (P, c, Q)" by fastforce theorem "\ P \ diverges c = {} \ \ pc(P, c, Q) \ sil (P, c, Q)" by fastforce theorem "\ P \ determ c \ \ sil (P, c, Q) \ pc(P, c, Q)" by fastforce text \ Comparing il and sil \ lemma "il (P, c, Q) \ sil (Q, c\, P)" by auto (* and the proof rules can be rewritten using...*) lemma "(c1 O c2)\ = c2\ O c1\" by blast lemma "(c1 \ c2)\ = c1\ \ c2\" by blast lemma "(c1 \ c2)\ = c1\ \ c2\" by blast lemma "(c\<^sup>*)\ = (c\)\<^sup>*" using rtrancl_converse by blast definition init :: state where [simp]: "init x = 0" definition is_eq :: "var \ int \ assertion" (infix "===" 55) where [simp]: "x === n = {\. \ x = n }" definition is_gt :: "var \ int \ assertion" (infix ">>>" 55) where [simp]: "x >>> n = {\. \ x > n }" definition inc :: "var \ command" ("++") where [simp]: "++ x = {(\, \') | \ \'. \' = \(x := \ x + 1)}" definition assign_const :: "var \ int \ command" where [simp]: "assign_const x n = {(\, \') | \ \'. \' = \(x := n)}" text \ Does the triple (x=n, ++x, x=n+1) hold? \ theorem "pc(x===n, ++x, x===n+1)" by auto theorem "sil(x===n, ++x, x===n+1)" by auto theorem "nt(x===n, ++x, x===n+1)" by auto theorem "il(x===n, ++x, x===n+1)" apply simp apply (metis fun_upd_same fun_upd_triv fun_upd_upd) done text \ Does the triple (x>n, ++x, x>n+1) hold? \ theorem "pc(x>>>n, ++x, x>>>n+1)" by auto theorem "sil(x>>>n, ++x, x>>>n+1)" by auto theorem "nt(x>>>n, ++x, x>>>n+1)" by auto theorem "il(x>>>n, ++x, x>>>n+1)" apply clarsimp apply (rule_tac x="\'(x := \' x - 1)" in exI) apply auto done text \ Does the triple (x>2, assign x 5, x==5) hold? \ theorem "pc(x>>>2, assign_const x 5, x===5)" by auto theorem "sil(x>>>2, assign_const x 5, x===5)" by auto theorem "il(x>>>2, assign_const x 5, x===5)" by force theorem "nt(x>>>2, assign_const x 5, x===5) \ False" by auto text \ Does the triple (x>2, assign x n, x==n) hold? \ theorem "pc(x>>>2, assign_const x n, x===n)" by auto theorem "sil(x>>>2, assign_const x n, x===n)" by auto theorem "nt(x>>>2, assign_const x n, x===n) \ False" by auto theorem "il(x>>>2, assign_const x n, x===n)" apply clarsimp apply (rule_tac x="\'(x := 3)" in exI) apply auto done text \ Does the triple (TRUE, assign x n, x==n) hold? \ theorem "pc(TRUE, assign_const x n, x===n)" by auto theorem "sil(TRUE, assign_const x n, x===n)" by auto theorem "il(TRUE, assign_const x n, x===n)" by force theorem "nt(TRUE, assign_const x n, x===n)" by auto text \ Does the triple (x>2, assign x 5, x>3) hold? \ theorem "pc(x>>>2, assign_const x 5, x>>>3)" by auto theorem "sil(x>>>2, assign_const x 5, x>>>3)" by auto theorem "nt(x>>>2, assign_const x 5, x>>>3) \ False" by auto theorem "il(x>>>2, assign_const x 5, x>>>3) \ False" apply clarsimp apply (rule_tac x="init(x := 4)" in exI) apply auto apply (drule fun_upd_eqD, simp) done text \ Does the triple (TRUE, assign x n \ assign x m, x==n \ x==m) hold? \ theorem "pc(TRUE, assign_const x n \ assign_const x m, (x===n) \ (x===m))" by auto theorem "sil(TRUE, assign_const x n \ assign_const x m, (x===n) \ (x===m))" by auto theorem "il(TRUE, assign_const x n \ assign_const x m, (x===n) \ (x===m))" by force theorem "nt(TRUE, assign_const x n \ assign_const x m, (x===n) \ (x===m))" by auto text \ Does the triple (x>n, ++x \ skip, x>n) hold? \ theorem "pc(x>>>n, ++x \ skip, x>>>n)" by auto theorem "sil(x>>>n, ++x \ skip, x>>>n)" by auto theorem "nt(x>>>n, ++x \ skip, x>>>n)" by auto theorem "il(x>>>n, ++x \ skip, x>>>n)" by auto definition assign :: "var \ (state \ int) \ command" where [simp]: "assign x e = {(\, \') | \ \'. \' = \(x := e \)}" theorem "pc(Q, assign x e, {\(x := e \) | \. \ \ Q})" by auto theorem "sil(Q, assign x e, {\(x := e \) | \. \ \ Q})" by auto theorem "il(Q, assign x e, {\(x := e \) | \. \ \ Q})" by auto theorem "nc(Q, assign x e, {\(x := e \) | \. \ \ Q})" oops datatype expr = Num "int" | Var "var" | Add "expr" "expr" fun subst_expr :: "var \ expr \ expr \ expr" where "subst_expr x e (Num n) = Num n" | "subst_expr x e (Var y) = (if y=x then e else Var y)" | "subst_expr x e (Add e1 e2) = Add (subst_expr x e e1) (subst_expr x e e2)" fun sem_expr :: "expr \ state \ int" where "sem_expr (Num n) _ = n" | "sem_expr (Var x) \ = \ x" | "sem_expr (Add e1 e2) \ = sem_expr e1 \ + sem_expr e2 \" datatype assn = Conj "assn" "assn" | TT | Eq "expr" "expr" fun subst :: "var \ expr \ assn \ assn" where "subst x e (Conj Q1 Q2) = Conj (subst x e Q1) (subst x e Q2)" | "subst x e TT = TT" | "subst x e (Eq e1 e2) = Eq (subst_expr x e e1) (subst_expr x e e2)" fun sem :: "assn \ state set" where "sem (Conj Q1 Q2) = sem Q1 \ sem Q2" | "sem TT = UNIV" | "sem (Eq e1 e2) = { \. sem_expr e1 \ = sem_expr e2 \ }" lemma sem_subst_expr: "sem_expr (subst_expr x e1 e) \ = sem_expr e (\(x := sem_expr e1 \))" by (induct e, auto) theorem hoare_assign_pc: "pc(sem(subst x e Q), assign x (sem_expr e), sem Q)" by (induct Q, auto simp add: sem_subst_expr) theorem hoare_assign_sil: "sil(sem(subst x e Q), assign x (sem_expr e), sem Q)" by (induct Q, auto simp add: sem_subst_expr) theorem hoare_assign_nc: "nc(sem(subst x e Q), assign x (sem_expr e), sem Q)" by (induct Q, auto simp add: sem_subst_expr) type_synonym heap = "int \ int option option" (* "Some (Some n)" means allocated *) (* "Some None" means deallocated *) (* "None" means never allocated *) type_synonym sl_state = "heap \ state" type_synonym sl_assertion = "sl_state set" type_synonym sl_command = "(sl_state \ sl_state) set" definition sl_skip where [simp]: "sl_skip \ { (\,\') | \ \'. \ = \' }" definition sl_alloc where [simp]: "sl_alloc x \ { ((h,s), (h(l := Some (Some v)), s(x := l))) | h s l v. h l \ {None, Some None} }" definition sl_free where [simp]: "sl_free x \ { ((h,s),(h(l := Some None),s)) | h s l. s x = l \ h l \ {None, Some None} }" fun sl_sil :: "(sl_assertion \ sl_command \ sl_assertion) \ bool" where "sl_sil (P, c, Q) = (\\ \ P. \\' \ Q. (\, \') \ c)" fun sl_il :: "(sl_assertion \ sl_command \ sl_assertion) \ bool" where "sl_il (P, c, Q) = (\\'\ Q. \\ \ P. (\, \') \ c)" definition emp where [simp]: "emp \ { (h,s) | h s. dom h = {} }" definition pointsto where [simp]: "pointsto x v \ { (h,s) | h s. \l. s x = l \ dom h = {l} \ h l = Some (Some v) }" definition dealloc where [simp]: "dealloc x \ { (h,s) | h s. \l. s x = l \ dom h = {l} \ h l = Some None }" definition eq where [simp]: "eq x y \ { (h,s) | h s. s x = s y }" lemma sil_alloc1: "sl_sil (emp, sl_alloc x, pointsto x v)" by (auto, metis dom_eq_singleton_conv fun_upd_same) lemma sil_alloc2: "sl_sil (dealloc y, sl_alloc x, eq x y \ pointsto x v)" by force lemma sil_free: "sl_sil (pointsto x e, sl_free x, dealloc x)" by simp lemma il_free: "sl_il (pointsto x e, sl_free x, dealloc x)" apply auto apply (rename_tac h' s) apply (rule_tac x="[s x \ Some e]" in exI) apply fastforce done end