Theory VC_KAD

(* Title: Verification Component Based on KAD
   Author: Victor Gomes, Georg Struth
   Maintainer: Victor Gomes <victor.gomes@cl.cam.ac.uk>
               Georg Struth <g.struth@sheffield.ac.uk> 
*)

section ‹Components Based on Kleene Algebra with Domain›

theory VC_KAD

imports KAD.Modal_Kleene_Algebra_Models "../P2S2R"      

begin

subsection‹Verification Component for Backward Reasoning›

text ‹This component supports the verification of simple while programs
in a partial correctness setting.›

unbundle no floor_ceiling_syntax

notation p2r (‹⌈_⌉›)
notation r2p (‹⌊_⌋›)

context antidomain_kleene_algebra
begin

subsubsection ‹Additional Facts for KAD›

lemma fbox_shunt: "d p ⋅ d q ≤ |x] t ⟷ d p ≤ ad q + |x] t"
  by (metis a_6 a_antitone' a_loc add_commute addual.ars_r_def am_d_def da_shunt2 fbox_def)

subsubsection ‹Syntax for Conditionals and Loops›

definition cond :: "'a ⇒ 'a ⇒ 'a ⇒ 'a" (‹if _ then _ else _ fi› [64,64,64] 63) where
  "if p then x else y fi = d p ⋅ x + ad p ⋅ y"

definition while :: "'a ⇒ 'a ⇒ 'a" (‹while _ do _ od› [64,64] 63) where
  "while p do x od = (d p ⋅ x)⋆ ⋅ ad p"

definition whilei :: "'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"

subsubsection ‹Basic Weakest (Liberal) Precondition Calculus›

text ‹In the setting of Kleene algebra with domain, the wlp operator is the forward modal box operator 
of antidomain Kleene algebra.›

lemma fbox_export1: "ad p + |x] q = |d p ⋅ x] q"
  using a_d_add_closure addual.ars_r_def fbox_def fbox_mult by auto

lemma fbox_export2: "|x] p ≤ |x ⋅ ad q] (d p ⋅ ad q)"
proof -
  {fix t
   have "d t ⋅ x ≤ x ⋅ d p ⟹ d t ⋅ x ⋅ ad q ≤ x ⋅ ad q ⋅ d p ⋅ ad q"
     by (metis (full_types) a_comm_var a_mult_idem ads_d_def am2 ds.ddual.mult_assoc phl_export2)
   hence "d t ≤ |x] p ⟹ d t ≤ |x ⋅ ad q] (d p ⋅ ad q)"
     by (metis a_closure' addual.ars_r_def ans_d_def dka.dsg3 ds.ddual.mult_assoc fbox_def fbox_demodalisation3)
  }
  thus ?thesis
    by (metis a_closure' addual.ars_r_def ans_d_def fbox_def order_refl)
qed

lemma fbox_export3: "|x ⋅ ad p] q = |x] (d p + d q)"
  using a_de_morgan_var_3 ds.ddual.mult_assoc fbox_def by auto

lemma fbox_seq [simp]: "|x ⋅ y] q = |x] |y] q"
  by (simp add: fbox_mult) 

lemma fbox_seq_var: "p' ≤ |y] q ⟹ p ≤ |x] p' ⟹ p ≤ |x ⋅ y] q"
proof -
  assume h1: "p ≤ |x] p'" and h2: "p' ≤ |y] q"
  hence "|x] p' ≤ |x] |y] q"
    by (simp add: dka.dom_iso fbox_iso)
  thus ?thesis
    by (metis h1 dual_order.trans fbox_seq)
qed

lemma fbox_cond_var [simp]: "|if p then x else y fi] q = (ad p + |x] q) ⋅ (d p + |y] q)"  
  using cond_def a_closure' ads_d_def ans_d_def fbox_add2 fbox_export1 by auto

lemma fbox_cond_aux1 [simp]: "d p ⋅ |if p then x else y fi] q = d p ⋅ |x] q"
proof -
  have "d p ⋅ |if p then x else y fi] q = d p ⋅ |x] q ⋅ (d p + d ( |y] q))"
    using a_d_add_closure addual.ars_r_def ds.ddual.mult_assoc fbox_def fbox_cond_var by auto
  thus ?thesis
    by (metis addual.ars_r_def am2 dka.dns5 ds.ddual.mult_assoc fbox_def)
qed

lemma fbox_cond_aux2 [simp]: "ad p ⋅ |if p then x else y fi] q = ad p ⋅ |y] q"
  by (metis cond_def a_closure' add_commute addual.ars_r_def ans_d_def fbox_cond_aux1)

lemma fbox_cond [simp]: "|if p then x else y fi] q = (d p ⋅ |x] q) + (ad p ⋅ |y] q)"
proof -
  have "|if p then x else y fi] q = (d p + ad p) ⋅ |if p then x else y fi] q"
    by (simp add: addual.ars_r_def)
  thus ?thesis
    by (metis  distrib_right' fbox_cond_aux1 fbox_cond_aux2)
qed

lemma fbox_cond_var2 [simp]: "|if p then x else y fi] q = if p then |x] q else |y] q fi"
  using cond_def fbox_cond by auto

lemma fbox_while_unfold: "|while t do x od] p = (d t + d p) ⋅ (ad t + |x] |while t do x od] p)"
  by (metis fbox_export1 fbox_export3 dka.dom_add_closed fbox_star_unfold_var while_def)

lemma fbox_while_var1: "d t ⋅ |while t do x od] p = d t ⋅ |x] |while t do x od] p"
  by (metis fbox_while_unfold a_mult_add ads_d_def dka.dns5 ds.ddual.mult_assoc join.sup_commute)

lemma fbox_while_var2: "ad t ⋅ |while t do x od] p ≤ d p"
proof - 
  have "ad t ⋅ |while t do x od] p = ad t ⋅ (d t + d p) ⋅ (ad t + |x] |while t do x od] p)"
    by (metis fbox_while_unfold ds.ddual.mult_assoc)
  also have "... =  ad t ⋅ d p ⋅ (ad t + |x] |while t do x od] p)"
    by (metis a_de_morgan_var_3 addual.ars_r_def dka.dom_add_closed s4)
  also have "... ≤ d p ⋅ (ad t + |x] |while t do x od] p)"
    using a_subid_aux1' mult_isor by blast
  finally show ?thesis
    by (metis a_de_morgan_var_3 a_mult_idem addual.ars_r_def ans4 dka.dsr5 dpdz.domain_1'' dual_order.trans fbox_def)
qed

lemma fbox_while: "d p ⋅ d t ≤ |x] p ⟹ d p ≤ |while t do x od] (d p ⋅ ad t)"
proof -
  assume "d p ⋅ d t ≤ |x] p"
  hence "d p ≤ |d t ⋅ x] p"
    by (simp add: fbox_export1 fbox_shunt)
  hence "d p ≤ |(d t ⋅ x)⋆] p"
    by (simp add: fbox_star_induct_var)
  thus ?thesis
    using order_trans while_def fbox_export2 by presburger
qed

lemma fbox_while_var: "d p = |d t ⋅ x] p ⟹ d p ≤ |while t do x od] (d p ⋅ ad t)"
  by (metis eq_refl fbox_export1 fbox_shunt fbox_while)
 
lemma fbox_whilei: "d p ≤ d i ⟹ d i ⋅ ad t ≤ d q ⟹ d i ⋅ d t ≤ |x] i ⟹ d p ≤ |while t inv i do x od] q"
proof -
  assume a1: "d p ≤ d i" and a2: "d i ⋅ ad t ≤ d q" and "d i ⋅ d t ≤ |x] i"
  hence "d i ≤ |while t inv i do x od] (d i ⋅ ad t)"
    by (simp add: fbox_while whilei_def)
  also have "... ≤ |while t inv i do x od] q"
    using a2 dka.dom_iso fbox_iso by fastforce
  finally show ?thesis
    using a1 dual_order.trans by blast
qed

text ‹The next rule is used for dealing with while loops after a series of sequential steps.›

lemma fbox_whilei_break: "d p ≤ |y] i ⟹ d i ⋅ ad t ≤ d q ⟹ d i ⋅ d t ≤ |x] i ⟹ d p ≤ |y ⋅ (while t inv i do x od)] q"
  apply (rule fbox_seq_var, rule fbox_whilei, simp_all, blast)
  using fbox_simp by auto

text ‹Finally we derive a frame rule.›

lemma fbox_frame: "d p ⋅ x ≤ x ⋅ d p ⟹ d q ≤ |x] t ⟹ d p ⋅ d q ≤ |x] (d p ⋅ d t)"    
  using dual.mult_isol_var fbox_add1 fbox_demodalisation3 fbox_simp by auto

lemma fbox_frame_var: "d p ≤ |x] p ⟹ d q ≤ |x] t ⟹ d p ⋅ d q ≤ |x] (d p ⋅ d t)"
  using fbox_frame fbox_demodalisation3 fbox_simp by auto   

end

subsubsection ‹Store and Assignment›

type_synonym 'a store = "string  ⇒ 'a"

notation rel_antidomain_kleene_algebra.fbox (‹wp›)
and rel_antidomain_kleene_algebra.fdia (‹relfdia›)

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

lemma assign_prop: "⌈λs. P (s (v := e s))⌉ ; (v ::= e) = (v ::= e) ; ⌈P⌉"
  by (auto simp add: p2r_def gets_def)
                                                                                 
lemma wp_assign [simp]: "wp (v ::= e) ⌈Q⌉ = ⌈λs. Q (s (v := e s))⌉"
  by (auto simp: rel_antidomain_kleene_algebra.fbox_def gets_def rel_ad_def p2r_def)

lemma wp_assign_var [simp]: "⌊wp (v ::= e) ⌈Q⌉⌋ = (λs. Q (s (v := e s)))"
  by (simp, auto simp: r2p_def p2r_def)

lemma wp_assign_det: "wp (v ::= e) ⌈Q⌉ = relfdia (v ::= e) ⌈Q⌉"
  by (auto simp add: rel_antidomain_kleene_algebra.fbox_def rel_antidomain_kleene_algebra.fdia_def gets_def p2r_def rel_ad_def, fast)
 
subsubsection ‹Simplifications›

notation rel_antidomain_kleene_algebra.ads_d (‹rdom›)

abbreviation spec_sugar :: "'a pred ⇒ 'a rel ⇒ 'a pred ⇒ bool" (‹PRE _ _ POST _› [64,64,64] 63) where
  "PRE P X POST Q ≡ rdom ⌈P⌉ ⊆ wp X ⌈Q⌉"

abbreviation cond_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_antidomain_kleene_algebra.cond ⌈P⌉ X Y"

abbreviation whilei_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_antidomain_kleene_algebra.whilei ⌈P⌉ ⌈I⌉ X"

lemma d_p2r [simp]: "rdom ⌈P⌉ = ⌈P⌉"
  by (simp add: p2r_def rel_antidomain_kleene_algebra.ads_d_def rel_ad_def)

lemma p2r_conj_hom_var_symm [simp]: "⌈P⌉ ; ⌈Q⌉ = ⌈P ⊓ Q⌉"
  by (simp add: p2r_conj_hom_var)

lemma p2r_neg_hom [simp]: "rel_ad ⌈P⌉ = ⌈- P⌉"
  by (simp add: rel_ad_def p2r_def)

lemma wp_trafo: "⌊wp X ⌈Q⌉⌋ = (λs. ∀s'. (s,s') ∈ X ⟶ Q s')"  
  by (auto simp: rel_antidomain_kleene_algebra.fbox_def rel_ad_def p2r_def r2p_def)

lemma wp_trafo_var: "⌊wp X ⌈Q⌉⌋ s = (∀s'. (s,s') ∈ X ⟶ Q s')"
  by (simp add: wp_trafo)

lemma wp_simp: "rdom ⌈⌊wp X Q⌋⌉ = wp X Q"
  by (metis d_p2r rel_antidomain_kleene_algebra.a_subid' rel_antidomain_kleene_algebra.addual.bbox_def rpr)

lemma wp_simp_var [simp]: "wp ⌈P⌉ ⌈Q⌉ = ⌈- P ⊔ Q⌉"
  by (simp add: rel_antidomain_kleene_algebra.fbox_def)

lemma impl_prop [simp]: "⌈P⌉ ⊆ ⌈Q⌉ ⟷ (∀s. P s ⟶  Q s)"
  by (auto simp: p2r_def)

lemma p2r_eq_prop [simp]: "⌈P⌉ = ⌈Q⌉ ⟷ (∀s. P s ⟷  Q s)"
  by (auto simp: p2r_def)

lemma impl_prop_var [simp]: "rdom ⌈P⌉ ⊆ rdom ⌈Q⌉ ⟷ (∀s. P s ⟶  Q s)"
  by simp     

lemma p2r_eq_prop_var [simp]: "rdom ⌈P⌉ = rdom ⌈Q⌉ ⟷ (∀s. P s ⟷  Q s)"
  by simp                                                     
 
lemma wp_whilei: "(∀s. P s ⟶ I s) ⟹ (∀s. (I ⊓ -T) s ⟶ Q s) ⟹ (∀s. (I ⊓ T) s ⟶ ⌊wp X ⌈I⌉⌋ s) 
                  ⟹ (∀s. P s ⟶ ⌊wp (WHILE T INV I DO X OD) ⌈Q⌉⌋ s)"
  apply (simp only: impl_prop_var[symmetric] wp_simp)
  by (rule rel_antidomain_kleene_algebra.fbox_whilei, simp_all, simp_all add: p2r_def)

end