Theory VC_KAT_scratch

(* Title: Program Correctness Component Based on Kleene Algebra with Tests
   Author: Victor Gomes, Georg Struth
   Maintainer: Victor Gomes <victor.gomes@cl.cam.ac.uk>
               Georg Struth <g.struth@sheffield.ac.uk> 
*)

section ‹Two Standalone Components›

theory VC_KAT_scratch
  imports Main
begin

subsection ‹Component Based on Kleene Algebra with Tests›

text ‹This component supports the verification and step-wise refinement of simple while programs
in a partial correctness setting.›

subsubsection ‹KAT: Definition and Basic Properties›

notation times (infixl  70)

class plus_ord = plus + ord +
  assumes less_eq_def: "x  y  x + y = y"
  and less_def: "x < y  x  y  x  y"

class dioid = semiring + one + zero + plus_ord +
  assumes add_idem [simp]: "x + x = x"
  and mult_onel [simp]: "1  x = x"
  and mult_oner [simp]: "x  1 = x"
  and add_zerol [simp]: "0 + x = x"
  and annil [simp]: "0  x = 0"
  and annir [simp]: "x  0 = 0"

begin

subclass monoid_mult 
  by (standard, simp_all)

subclass order
  apply (standard, simp_all add: less_def less_eq_def add_commute)
  apply force
  by (metis add_assoc)

lemma mult_isol: "x  y  z  x  z  y"
  by (metis distrib_left less_eq_def)

lemma mult_isor: "x  y  x  z  y  z"
  by (metis distrib_right less_eq_def)
                                         
lemma add_iso: "x  y  x + z  y + z"
  by (metis (no_types, lifting) abel_semigroup.commute add.abel_semigroup_axioms add.semigroup_axioms add_idem less_eq_def semigroup.assoc)

lemma add_lub: "x + y  z  x  z  y  z"
  by (metis add_assoc add.left_commute add_idem less_eq_def)

end

class kleene_algebra = dioid + 
  fixes star :: "'a  'a" (‹_ [101] 100)
  assumes star_unfoldl: "1 + x  x  x"  
  and star_unfoldr: "1 + x  x  x"
  and star_inductl: "z + x  y  y  x  z  y"
  and star_inductr: "z + y  x  y  z  x  y"

begin

lemma star_sim: "x  y  z  x  x  y  z  x"
proof - 
  assume "x  y  z  x"
  hence "x + z  x  y  x + z  z  x"
    by (metis add_lub distrib_left eq_refl less_eq_def mult_assoc)
  also have  "...  z  x"
    using add_lub mult_isor star_unfoldr by fastforce
  finally show ?thesis
    by (simp add: star_inductr) 
qed

end

class kat = kleene_algebra +
  fixes at :: "'a  'a" 
  assumes test_one [simp]: "at (at 1) = 1"
  and test_mult [simp]: "at (at (at (at x)  at (at y))) = at (at y)  at (at x)" 
  and test_mult_comp [simp]: "at x  at (at x) = 0"
  and test_de_morgan: "at x + at y = at (at (at x)  at (at y))"

begin

definition t_op :: "'a  'a" (t_› [100] 101) where
  "t x = at (at x)"

lemma t_n [simp]: "t (at x) = at x"
  by (metis add_idem test_de_morgan test_mult t_op_def)

lemma t_comm: "t x  t y = t y  t x"
  by (metis add_commute test_de_morgan test_mult t_op_def)

lemma t_idem [simp]: "t x  t x = t x"
  by (metis add_idem test_de_morgan test_mult t_op_def)

lemma t_mult_closed [simp]: "t (t x  t y) = t x  t y"
  using t_comm t_op_def by auto

subsubsection‹Propositional Hoare Logic›

definition H :: "'a  'a  'a  bool" where
  "H p x q  t p  x  x  t q"

definition if_then_else :: "'a  'a  'a  'a" (if _ then _ else _ fi [64,64,64] 63) where
  "if p then x else y fi = t p  x + at p  y"

definition while :: "'a  'a  'a" (while _ do _ od [64,64] 63) where
  "while p do x od = (t p  x)  at p"

definition while_inv :: "'a  'a  'a  'a" (while _ inv _ do _ od [64,64,64] 63) where
  "while p inv i do x od = while p do x od"

lemma H_skip: "H p 1 p"
  by (simp add: H_def)

lemma H_cons: "t p  t p'  t q'  t q  H p' x q'  H p x q"
  by (meson H_def mult_isol mult_isor order.trans)

lemma H_seq: "H r y q  H p x r   H p (x  y) q"
proof -
  assume h1: "H p x r" and h2: "H r y q"  
  hence h3: "t p  x  x  t r" and h4: "t r  y  y  t q"
    using H_def apply  blast using H_def h2 by blast
  hence "t p  x  y  x  t r  y"
    using mult_isor by blast
  also have "...  x  y  t q"
    by (simp add: h4 mult_isol mult_assoc)
  finally show ?thesis
    by (simp add: H_def mult_assoc)
qed

lemma H_cond: "H (t p  t r) x q  H (t p  at r) y q  H p (if r then x else y fi) q"
proof -
  assume h1: "H (t p  t r) x q" and h2: "H (t p  at r) y q"
  hence h3: "t r  t p  t r  x  t r  x  t q" and h4: "at r  t p  at r  y  at r  y  t q"
    by (simp add: H_def mult_isol mult_assoc, metis H_def h2 mult_isol mult_assoc t_mult_closed t_n)
  hence h5: "t p  t r  x  t r  x  t q" and  h6: "t p  at r  y  at r  y  t q"
    by (simp add: mult_assoc t_comm, metis h4 mult_assoc t_comm t_idem t_n)
  have "t p  (t r  x + at r  y) = t p  t r  x + t p  at r  y"
    by (simp add: distrib_left mult_assoc)
  also have "...  t r  x  t q + t p  at r  y"
    using h5 add_iso by blast
  also have "...  t r  x  t q + at r  y  t q"
    by (simp add: add_commute h6 add_iso)
  finally show ?thesis
    by (simp add: H_def if_then_else_def distrib_right)
qed

lemma H_loop: "H (t p  t r) x p  H p (while r do x od) (t p  at r)"
proof - 
  assume  "H (t p  t r) x p"
  hence "t r  t p  t r  x  t r  x  t p"
    by (metis H_def distrib_left less_eq_def mult_assoc t_mult_closed)
  hence "t p  t r  x  t r  x  t p"
    by (simp add: mult_assoc t_comm)
  hence "t p  (t r  x)  at r  (t r  x)  t p  at r"
    by (metis mult_isor star_sim mult_assoc)
  hence "t p  (t r  x)  at r  (t r  x)  at r  t p  at r"
    by (metis mult_assoc t_comm t_idem t_n)
  thus ?thesis
    by (metis H_def mult_assoc t_mult_closed t_n while_def)
qed

lemma H_while_inv: "t p  t i  t i  at r  t q  H (t i  t r) x i  H p (while r inv i do x od) q"
  by (metis H_cons H_loop t_mult_closed t_n while_inv_def)

end

subsubsection‹Soundness and Relation KAT›

notation relcomp (infixl ; 70)

interpretation rel_d: dioid Id "{}" "(∪)" "(;)" "(⊆)" "(⊂)" 
  by (standard, auto)

lemma (in dioid) power_inductl: "z + x  y  y  x ^ i  z  y"
  apply (induct i; clarsimp simp add: add_lub)
  by (metis local.dual_order.trans local.mult_isol mult_assoc)

lemma (in dioid) power_inductr: "z + y  x  y  z  x ^ i  y"
  apply (induct i; clarsimp simp add: add_lub)
  proof -
    fix i
    assume "z  x ^ i  y" "z  y" "y  x  y"
    hence "(z  x ^ i)  x  y"
      using local.dual_order.trans local.mult_isor by blast
    thus "z  (x  x ^ i)  y"
      by (simp add: mult_assoc local.power_commutes)
  qed

lemma power_is_relpow: "rel_d.power X i = X ^^ i"
  by (induct i, simp_all add: relpow_commute)

lemma rel_star_def: "X^* = (i. rel_d.power X i)"
  by (simp add: power_is_relpow rtrancl_is_UN_relpow)

lemma rel_star_contl: "X ; Y^* = (i. X ; rel_d.power Y i)"
  by (simp add: rel_star_def relcomp_UNION_distrib)

lemma rel_star_contr: "X^* ; Y = (i. (rel_d.power X i) ; Y)"
  by (simp add: rel_star_def relcomp_UNION_distrib2)

definition rel_at :: "'a rel  'a rel" where 
  "rel_at X = Id  - X"  

interpretation rel_kat: kat Id "{}" "(∪)" "(;)" "(⊆)" "(⊂)" rtrancl rel_at
  apply standard 
  apply auto[2]
  by (auto simp: rel_star_contr rel_d.power_inductl rel_star_contl  SUP_least rel_d.power_inductr rel_at_def)

subsubsection‹Embedding Predicates in Relations›

type_synonym 'a pred = "'a  bool"

abbreviation p2r :: "'a pred  'a rel" (_) where
  "P  {(s,s) |s. P s}"

lemma t_p2r [simp]: "rel_kat.t_op P = P"
  by (auto simp add: rel_kat.t_op_def rel_at_def)
 
lemma p2r_neg_hom [simp]: "rel_at P = λs. ¬ P s" 
  by (auto simp: rel_at_def)

lemma p2r_conj_hom [simp]: "P  Q = λs.  P s  Q s"
  by auto 

lemma p2r_conj_hom_var [simp]: "P ; Q = λs. P s  Q s" 
  by auto 

lemma p2r_disj_hom [simp]: "P  Q = λs. P s  Q s"
  by auto 

lemma impl_prop [simp]: "P  Q  (s. P s   Q s)"
  by auto 

subsubsection ‹Store and Assignment›

type_synonym 'a store = "string   'a"

definition gets :: "string  ('a store  'a)  'a store rel" (‹_ ::= _› [70, 65] 61) where 
  "v ::= e = {(s, s(v := e s)) |s. True}"

lemma H_assign: "rel_kat.H λs. P (s (v := e s)) (v ::= e) P"
  by (auto simp: gets_def rel_kat.H_def rel_kat.t_op_def rel_at_def)

lemma H_assign_var: "(s. P s  Q (s (v := e s)))  rel_kat.H P (v ::= e) Q"
  by (auto simp: gets_def rel_kat.H_def rel_kat.t_op_def rel_at_def)

abbreviation H_sugar :: "'a pred  'a rel  'a pred  bool" (PRE _ _ POST _› [64,64,64] 63) where
  "PRE P X POST Q  rel_kat.H P X Q"

abbreviation if_then_else_sugar :: "'a pred  'a rel  'a rel  'a rel" (IF _ THEN _ ELSE _ FI [64,64,64] 63) where
  "IF P THEN X ELSE Y FI  rel_kat.if_then_else P X Y"

abbreviation while_inv_sugar :: "'a pred  'a pred  'a rel  'a rel" (WHILE _ INV _ DO _ OD [64,64,64] 63) where
  "WHILE P INV I DO X OD  rel_kat.while_inv P I X"

subsubsection ‹Verification Example›

lemma euclid:
  "PRE (λs::nat store. s ''x'' = x  s ''y'' = y)
   (WHILE (λs. s ''y''  0) INV (λs. gcd (s ''x'') (s ''y'') = gcd x y) 
    DO
     (''z'' ::= (λs. s ''y''));
     (''y'' ::= (λs. s ''x'' mod s ''y''));
     (''x'' ::= (λs. s ''z''))
    OD)
   POST (λs. s ''x'' = gcd x y)"
  apply (rule rel_kat.H_while_inv, simp_all, clarsimp)
  apply (intro rel_kat.H_seq)
  apply (subst H_assign, simp)+
  apply (rule H_assign_var)
  using gcd_red_nat by auto

subsubsection ‹Definition of Refinement KAT›

class rkat = kat +
  fixes R :: "'a  'a  'a"
  assumes R1: "H p (R p q) q"
  and R2: "H p x q  x  R p q"

begin

subsubsection ‹Propositional Refinement Calculus›

lemma R_skip: "1  R p p"
  by (simp add: H_skip R2)

lemma R_cons: "t p  t p'  t q'  t q  R p' q'  R p q"
  by (simp add: H_cons R2 R1)

lemma R_seq: "(R p r)  (R r q)  R p q"
  using H_seq R2 R1 by blast

lemma R_cond: "if v then (R (t v  t p) q) else (R (at v  t p) q) fi  R p q"
  by (metis H_cond R1 R2 t_comm t_n)

lemma R_loop: "while q do (R (t p  t q) p) od   R p (t p  at q)"
  by (simp add: H_loop R2 R1)

end

subsubsection ‹Soundness and Relation RKAT›

definition rel_R :: "'a rel  'a rel  'a rel" where 
  "rel_R P Q = {X. rel_kat.H P X Q}"

interpretation rel_rkat: rkat Id "{}" "(∪)"  "(;)" "(⊆)" "(⊂)" rtrancl rel_at rel_R
  by (standard, auto simp: rel_R_def rel_kat.H_def rel_kat.t_op_def rel_at_def)

subsubsection ‹Assignment Laws›

lemma R_assign: "(s. P s  Q (s (v := e s)))  (v ::= e)  rel_R P Q"
  by (simp add: H_assign_var rel_rkat.R2)

lemma R_assignr: "(s. Q' s  Q (s (v := e s)))  (rel_R P Q') ; (v ::= e)  rel_R P Q"
proof -
  assume a1: "s. Q' s  Q (s(v := e s))"
  have "p pa cs f. fa. (p fa  cs ::= f  rel_R p pa)  (¬ pa (fa(cs := f fa::'a))  cs ::= f  rel_R p pa)"
    using R_assign by blast
  hence "v ::= e  rel_R Q' Q" 
    using a1 by blast
  thus ?thesis 
    by (meson dual_order.trans rel_d.mult_isol rel_rkat.R_seq)
qed

lemma R_assignl: "(s. P s  P' (s (v := e s)))  (v ::= e) ; (rel_R P' Q)  rel_R P Q"
proof -
  assume a1: "s. P s  P' (s(v := e s))"
  have "p pa cs f. fa. (p fa  cs ::= f  rel_R p pa)  (¬ pa (fa(cs := f fa::'a))  cs ::= f  rel_R p pa)"
    using R_assign by blast
  then have "v ::= e  rel_R P P'"
    using a1 by blast
  then show ?thesis
    by (meson dual_order.trans rel_d.mult_isor rel_rkat.R_seq)
qed  

subsubsection ‹Refinement Example›

lemma var_swap_ref1: 
  "rel_R λs. s ''x'' = a  s ''y'' = b λs. s ''x'' = b  s ''y'' = a 
    (''z'' ::= (λs. s ''x'')); rel_R λs. s ''z'' = a  s ''y'' = b λs. s ''x'' = b  s ''y'' = a"
  by (rule R_assignl, auto) 

lemma var_swap_ref2: 
  "rel_R λs. s ''z'' = a  s ''y'' = b λs. s ''x'' = b  s ''y'' = a 
    (''x'' ::= (λs. s ''y'')); rel_R λs. s ''z'' = a  s ''x'' = b λs. s ''x'' = b  s ''y'' = a"
  by (rule R_assignl, auto)

lemma var_swap_ref3:  
  "rel_R λs. s ''z'' = a  s ''x'' = b λs. s ''x'' = b  s ''y'' = a 
    (''y'' ::= (λs. s ''z'')); rel_R λs. s ''x'' = b  s ''y'' = a λs. s ''x'' = b  s ''y'' = a" 
  by (rule R_assignl, auto)

lemma var_swap_ref_var: 
  "rel_R λs. s ''x'' = a  s ''y'' = b λs. s ''x'' = b  s ''y'' = a 
    (''z'' ::= (λs. s ''x'')); (''x'' ::= (λs. s ''y'')); (''y'' ::= (λs. s ''z''))"
  using var_swap_ref1 var_swap_ref2 var_swap_ref3 rel_rkat.R_skip  by fastforce

end