(* The Isabelle/HOL proof script accompanying the paper "The Laws of Programming Unify Process Calculi" *) theory LawsOfProgrammingUnifyProcessCalculi imports Main begin declare [[ smt_solver = remote_z3]] declare [[ smt_timeout = 60 ]] declare [[ z3_options = "-memory:500" ]] section {* The basic algebra *} locale basicalgebra = fixes refinement :: "'a \ 'a \ bool" (infix "\" 50) and disjunction :: "'a \ 'a \ 'a" (infixl "\" 65) and conjunction :: "'a \ 'a \ 'a" (infixl "\" 70) and semicolon :: "'a \ 'a \ 'a" (infixl ";" 80) and concurrency :: "'a \ 'a \ 'a" (infixl "\" 80) and bottom :: "'a" ("\") and top :: "'a" ("\") and skip :: "'a" and iteration :: "'a \ 'a" ("_\<^sup>\" [101] 100) assumes refinement_reflexive: "x\x" and refinement_transitive: "x\y \ y\z \ x\z" and refinement_antisymmetric: "x\y \ y\x \ x=y" and disj_increasing1: "x \ x\y" and disj_increasing2: "y \ x\y" and disj_lub: "x\z \ y\z \ x\y \ z" and conj_decreasing1: "x\y \ x" and conj_decreasing2: "x\y \ y" and conj_glb: "x \ y \ x \ z \ x \ y\z" (* The table *) assumes disjunction_commutative: "x\y = y\x" and disjunction_associative: "x\(y\z) = (x\y)\z" and disjunction_idempotent: "x\x = x" and disjunction_left_unit: "\\x = x" and disjunction_right_unit: "x\\ = x" and disjunction_left_zero: "\\x = \" and disjunction_right_zero: "x\\ = \" and conjunction_commutative: "x\y = y\x" and conjunction_associative: "x\(y\z) = (x\y)\z" and conjunction_idempotent: "x\x = x" and conjunction_left_unit: "\\x = x" and conjunction_right_unit: "x\\ = x" and conjunction_left_zero: "\\x = \" and conjunction_right_zero: "x\\ = \" and semicolon_associative: "x;(y;z) = (x;y);z" and semicolon_left_unit: "skip;x = x" and semicolon_right_unit: "x;skip = x" and semicolon_left_zero: "\;x = \" and semicolon_right_zero: "x;\ = \" and concurrency_commutative: "x\y = y\x" and concurrency_associative: "x\(y\z) = (x\y)\z" and concurrency_left_unit: "skip\x = x" and concurrency_right_unit: "x\skip = x" and concurrency_left_zero: "\\x = \" and concurrency_right_zero: "x\\ = \" (* Distribution laws *) fixes distr_through_disj_p :: "('a \ 'a \ 'a) \ bool" defines "distr_through_disj_p f \ (\ x y z . (f x (y\z) = (f x y) \ (f x z)) \ (f (x\y) z) = ((f x z) \ (f y z)))" assumes disj_distr_through_disj: "distr_through_disj_p (op \)" and conj_distr_through_disj: "distr_through_disj_p (op \)" and semicolon_distr_through_disj: "distr_through_disj_p (op ;)" and concurrency_distr_through_disj: "distr_through_disj_p (op \)" and exchange: "(p\q);(r\s) \ (p;r)\(q;s)" (* Kleene star laws *) assumes iter1: "skip \ (p;p\<^sup>\) \ p\<^sup>\" and iter2: "p \ (q;r) \ r \ q\<^sup>\;p \ r" and iter3: "skip \ (p\<^sup>\;p) \ p\<^sup>\" and iter4: "p \ (r;q) \ r \ p;q\<^sup>\ \ r" (* Auxiliary definitions. They appear here because otherwise the sublocale handling will raise problems later. *) fixes lessthan :: "'a \ 'a \ bool" (infix "\" 50) defines "x\y \ (x\y) \ \(y\x)" fixes monotone_p :: "('a \ 'a \ 'a) \ bool" defines "monotone_p f \ (\ x y z . (x \ y \ (f x z) \ (f y z))) \ (\ x y z . (y \ z \ (f x y) \ (f x z)))" (* Don't define backsemicolon x y \ y;x explicitly - it will make automation difficult. *) begin text {* Simple consequences of the laws. *} lemma conj_disj_relationship: "q=p\q \ p=p\q" by (metis conj_decreasing1 conj_decreasing2 conj_glb disj_increasing1 disj_increasing2 disj_lub refinement_antisymmetric refinement_reflexive) lemma refinement_disj: "x\y \ y=x\y" by (metis disj_increasing1 disj_increasing2 disj_lub refinement_antisymmetric refinement_reflexive) lemma refinement_conj: "x\y \ x=x\y" by (metis conj_decreasing2 conj_disj_relationship refinement_disj) lemma bottom_least: "\\x" by (metis disj_increasing2 disjunction_right_unit) lemma top_greatest: "x\\" by (metis conj_decreasing1 conjunction_left_unit) lemma iter_unfold1: "skip \ p\<^sup>\" by (metis disj_increasing1 iter1 refinement_transitive) lemma iter_unfold2: "p;p\<^sup>\ \ p\<^sup>\" by (metis disj_increasing2 iter1 refinement_transitive) text {* Any operator that distributes through disjunction is monotone. *} lemma distr_through_disj_implies_monotone: "distr_through_disj_p f \ monotone_p f" by (metis (full_types) distr_through_disj_p_def monotone_p_def refinement_disj) text {* The binary operators are therefore monotone. *} lemma disj_monotone: "monotone_p (op \)" by (metis disj_distr_through_disj distr_through_disj_implies_monotone) lemma conj_monotone: "monotone_p (op \)" by (metis conj_distr_through_disj distr_through_disj_implies_monotone) lemma semicolon_monotone: "monotone_p (op ;)" by (metis semicolon_distr_through_disj distr_through_disj_implies_monotone) lemma concurrency_monotone: "monotone_p (op \)" by (metis concurrency_distr_through_disj distr_through_disj_implies_monotone) text {* Lemmas that aid automation. *} lemma disj_monotone1: "x \ y \ x\z \ y\z" by (metis monotone_p_def disj_monotone) lemma conj_monotone1: "x \ y \ x\z \ y\z" by (metis monotone_p_def conj_monotone) lemma semicolon_monotone1: "x \ y \ x;z \ y;z" by (metis monotone_p_def semicolon_monotone) lemma concurrency_monotone1: "x \ y \ x\z \ y\z" by (metis monotone_p_def concurrency_monotone) lemma disj_monotone2: "y \ z \ x\y \ x\z" by (metis monotone_p_def disj_monotone) lemma conj_monotone2: "y \ z \ x\y \ x\z" by (metis monotone_p_def conj_monotone) lemma semicolon_monotone2: "y \ z \ x;y \ x;z" by (metis monotone_p_def semicolon_monotone) lemma concurrency_monotone2: "y \ z \ x\y \ x\z" by (metis monotone_p_def concurrency_monotone) text {* The small exchange laws hold. *} lemma small_exchange1: "x;(y\z) \ (x;y)\z" by (metis concurrency_right_unit exchange semicolon_left_unit) lemma small_exchange2: "(x\y);z \ x\(y;z)" by (metis concurrency_left_unit exchange semicolon_right_unit) text {* Sequential composition is a special case of concurrent composition *} lemma seq_refines_conc: "x;y \ x\y" by (metis concurrency_right_unit semicolon_left_unit small_exchange2) text {* Any monotone operator exchanges with conjunction. *} lemma monotone_op_exchanges_with_conj: "monotone_p f \ f (w \ x) (y \ z) \ (f w y)\(f x z)" proof - assume ap: "monotone_p f" have a: "f (w \ x) (y \ z) \ f w y" by (metis monotone_p_def ap conj_decreasing1 refinement_transitive) have b: "f (w \ x) (y \ z) \ f x z" by (metis monotone_p_def ap conjunction_commutative conj_decreasing1 refinement_transitive) from a b show ?thesis by (metis conj_disj_relationship conjunction_associative refinement_disj) qed text {* In particular, sequential composition exchanges with conjunction. *} lemma conjunction_exchange: "(w\x);(y\z) \ (w;y)\(x;z)" by (metis monotone_op_exchanges_with_conj semicolon_monotone) text {* The dual property says that a monotone operator reverse-exchanges with disjunction. *} lemma monotone_op_reverse_exchanges_with_disj: "monotone_p f \ (f w y)\(f x z) \ f (w \ x) (y \ z)" proof - assume ap: "monotone_p f" have a: " f w y \ f (w \ x) (y \ z)" by (metis monotone_p_def ap disj_increasing1 refinement_transitive) have b: "f x z \ f (w \ x) (y \ z)" by (metis monotone_p_def ap disjunction_commutative disj_increasing1 refinement_transitive) from a b show ?thesis by (metis disjunction_associative refinement_disj) qed text {* Time reversal duality (opposition). *} lemma time_reversal: "basicalgebra (op \) (op \) (op \) (\ x y . y;x) (op \) \ \ skip iteration" apply (rule basicalgebra.intro) apply (rule refinement_reflexive) apply (metis refinement_transitive) apply (metis refinement_antisymmetric) apply (rule disj_increasing1) apply (rule disj_increasing2) apply (metis disj_lub) apply (rule conj_decreasing1) apply (rule conj_decreasing2) apply (metis conj_glb) apply (metis disjunction_commutative) apply (metis disjunction_associative) apply (metis disjunction_idempotent) apply (metis disjunction_left_unit) apply (metis disjunction_right_unit) apply (metis disjunction_left_zero) apply (metis disjunction_right_zero) apply (metis conjunction_commutative) apply (metis conjunction_associative) apply (metis conjunction_idempotent) apply (metis conjunction_left_unit) apply (metis conjunction_right_unit) apply (metis conjunction_left_zero) apply (metis conjunction_right_zero) apply (metis semicolon_associative) apply (metis semicolon_right_unit) apply (metis semicolon_left_unit) apply (metis semicolon_right_zero) apply (metis semicolon_left_zero) apply (metis concurrency_commutative) apply (metis concurrency_associative) apply (metis concurrency_left_unit) apply (metis concurrency_right_unit) apply (metis concurrency_left_zero) apply (metis concurrency_right_zero) apply (metis disj_distr_through_disj distr_through_disj_p_def) apply (metis conj_distr_through_disj distr_through_disj_p_def) apply (metis semicolon_distr_through_disj distr_through_disj_p_def) apply (metis concurrency_distr_through_disj distr_through_disj_p_def) apply (metis exchange) apply (metis iter3) apply (metis iter4) apply (metis iter1) by (metis iter2) text {* Familiar algebraic structures. *} lemma is_partial_order: "class.order (op \) (op \)" apply (rule class.order.intro) apply (rule class.preorder.intro) apply (metis lessthan_def) apply (metis refinement_reflexive) apply (metis refinement_transitive) apply (rule class.order_axioms.intro) apply (metis refinement_antisymmetric) done lemma is_lattice: "class.lattice (op \) (op \) (op \) (op \)" apply (rule class.lattice.intro) apply (rule class.semilattice_inf.intro) apply (rule is_partial_order) apply (rule class.semilattice_inf_axioms.intro) apply (metis conj_decreasing1) apply (metis conj_decreasing1 conjunction_commutative) apply (metis conj_glb) apply (rule class.semilattice_sup.intro) apply (rule is_partial_order) apply (rule class.semilattice_sup_axioms.intro) apply (metis disj_increasing1) apply (metis disj_increasing1 disjunction_commutative) by (metis disj_lub) lemma is_bounded_lattice: "class.bounded_lattice (op \) (op \) (op \) (op \) \ \" apply (rule class.bounded_lattice.intro) apply (rule class.bounded_lattice_bot.intro) apply (rule is_lattice) apply (rule class.bot.intro) apply (rule is_partial_order) apply (rule class.bot_axioms.intro) apply (rule bottom_least) apply (rule class.bounded_lattice_top.intro) apply (rule is_lattice) apply (rule class.top.intro) apply (rule is_partial_order) apply (rule class.top_axioms.intro) by (metis disjunction_right_zero refinement_disj) end text {* Make the time reversed versions of the theorems available. *} sublocale basicalgebra < time_reverse!: basicalgebra "(op \)" "(op \)" "(op \)" "(\ x y . y;x)" "(op \)" "\" "\" "skip" "iteration" apply (rule time_reversal) apply (rule distr_through_disj_p_def) apply (rule lessthan_def) by (rule monotone_p_def) section {* Hoare logic *} locale hoarelogic = basicalgebra begin abbreviation (input) hoare_triple :: "'a \ 'a \ 'a \ bool" ("_\_\_" [54,54,54] 53) where "p\q\r \ p;q \ r" theorem Hskip: "p\skip\p" by (metis refinement_reflexive semicolon_right_unit) theorem Hseq: "p\q\r \ r\q'\s \ p\q;q'\s" by (metis refinement_transitive semicolon_associative semicolon_monotone1) theorem Hchoice: "p\q\r \ p\q'\r \ p\q\q'\r" by (metis disj_lub distr_through_disj_p_def semicolon_distr_through_disj) theorem Hconj': "p\q\r \ p'\q'\r' \ p\p'\q\q'\r\r'" by (metis conj_decreasing1 conj_decreasing2 conj_glb conjunction_exchange refinement_transitive) theorem Hiter: "p\q\p \ p\q\<^sup>\\p" by (metis disjunction_commutative iter4 refinement_disj refinement_reflexive) theorem Hcons: "p'\p \ p\q\r \ r\r' \ p'\q\r'" by (metis refinement_transitive semicolon_monotone1) theorem Hconj: "p\q\r \ p'\q\r' \ p\p'\q\r\r'" by (metis Hconj' conjunction_idempotent) theorem Hdisj: "p\q\r \ p'\q\r' \ p\p'\q\r\r'" by (smt disjunction_associative disjunction_commutative distr_through_disj_p_def refinement_disj semicolon_distr_through_disj) theorem Hconc: "p\q\r \ p'\q'\r' \ p\p'\q\q'\r\r'" by (metis concurrency_monotone2 concurrency_monotone1 refinement_transitive exchange) theorem Hframe: "p\q\r \ f\p\q\f\r" by (metis concurrency_monotone2 refinement_transitive small_exchange2) theorem Hseqframe: "p\q\r \ f;p\q\f;r" by (metis semicolon_associative semicolon_monotone2) end text {* Make the time reversed versions of the theorems available. *} sublocale hoarelogic < time_reverse!: hoarelogic "(op \)" "(op \)" "(op \)" "(\ x y . y;x)" "(op \)" "\" "\" "skip" "iteration" apply (rule hoarelogic.intro) apply (rule time_reversal) apply (rule distr_through_disj_p_def) apply (rule lessthan_def) by (rule monotone_p_def) text {* Time-reversing the Hoare calculus yields another calculus. *} locale newcalculus = hoarelogic begin theorem HseqTimeReverse: "q';r \ s \ q;p \ r \ (q';q);p \ s" by (metis time_reverse.Hseq) end section {* Milner-style semantics *} locale milner = hoarelogic begin abbreviation (input) milner_triple :: "'a \ 'a \ 'a \ bool" ("_-_\_" [54,54,54] 53) where "p-q\r \ q;r \ p" theorem Maction: "p-p\skip" by (metis Hskip) theorem Mseq1: "p-q\r \ p;p'-q\r;p'" by (metis time_reverse.Hseqframe) theorem Mseq2: "p-q\skip \ p;p'-q\p'" by (metis Mseq1 semicolon_left_unit) theorem Mprefixing: "p;p'-p\p'" by (metis Maction Mseq2) abbreviation (input) milner_rearrangement :: "'a \ 'a \ bool" ("_-\_" [54,54] 53) where "p-\q \ p-skip\q" lemma rearrangement: "p-\q \ q \ p" by (metis semicolon_left_unit) theorem Mchoice: "p\p'-\p" by (metis disj_increasing1 rearrangement) theorem Mchoice2: "p\p'-\p'" by (metis Mchoice disjunction_commutative) theorem Miter1: "p\<^sup>\-\skip" by (metis iter_unfold1 rearrangement) theorem Miter2: "p\<^sup>\-\p;p\<^sup>\" by (metis iter_unfold2 rearrangement) theorem Mconc1: "p-q\r \ p\p'-q\r\p'" by (metis concurrency_commutative time_reverse.Hframe) theorem Mconc2: "p-q\skip \ p\p'-q\p'" by (metis Mconc1 concurrency_left_unit) theorem Mconc3: "p-q\r \ p'\p-q\p'\r" by (metis Mconc1 concurrency_commutative) theorem Mconc4: "p-q\skip \ p'\p-q\p'" by (metis Mconc2 concurrency_commutative) theorem Mseq: "p-q\r \ r-q'\s \ p-q;q'\s" by (metis time_reverse.Hseq) theorem Mchoice': "p-q\r \ p\p'-q\r" by (metis Mseq Mchoice semicolon_left_unit) theorem Mcons: "p-\p' \ p'-q\r \ r-\r' \ p-q\r'" by (metis rearrangement time_reverse.Hcons) end text {* Make the time reversed versions of the theorems available. *} sublocale milner < time_reverse!: milner "(op \)" "(op \)" "(op \)" "(\ x y . y;x)" "(op \)" "\" "\" "skip" "iteration" apply (rule milner.intro) apply (rule hoarelogic.intro) apply (rule time_reversal) apply (rule distr_through_disj_p_def) apply (rule lessthan_def) by (rule monotone_p_def) section {* Kahn's natural semantics *} locale kahn = milner begin abbreviation (input) kahn_triple :: "'a \ 'a \ 'a \ bool" ("<_,_>\_" [54,54,54] 53) where "\s' \ s' \ s;p" lemma Kimprovement: "p \ p' \ \s' \ \s'" by (metis refinement_transitive semicolon_monotone2) theorem Kskip: "\s" by (metis refinement_reflexive semicolon_right_unit) theorem Kseq: "\s' \ \s'' \ \s''" by (metis refinement_transitive semicolon_associative semicolon_monotone1) theorem Kchoice: "\s' \ p',s>\s'" by (metis disj_increasing1 refinement_transitive semicolon_monotone2) theorem Kchoice': "\s' \ p',s>\s'" by (metis Kchoice disjunction_commutative) theorem Kiter1: "\,s>\s" by (metis Kimprovement iter_unfold1 refinement_reflexive semicolon_right_unit) theorem Kiter2: "\s' \ \,s'>\s'' \ \,s>\s''" proof - assume a: "\s'" assume b: "\,s'>\s''" from a b have c: "\,s>\s''" by (rule Kseq) from iter_unfold2 c show "\,s>\s''" by (rule Kimprovement) qed theorem Kconc1: "\s' \ \s'' \ p',s>\s''" by (metis Kimprovement Kseq seq_refines_conc) theorem Kconc2: "\s' \ \s'' \ p',s>\s''" by (metis Kconc1 concurrency_commutative) end