Theory SepLogK_VCG

theory SepLogK_VCG 
imports SepLogK_Hoare
begin
  
lemmas conseqS = conseq[where k=1, simplified]

datatype acom =
  Askip                  (SKIP) |
  Aassign vname aexp     ((_ ::= _) [1000, 61] 61) |
  Aseq   acom acom       (‹_;;/ _›  [60, 61] 60) | 
  Aif bexp acom acom     ((IF _/ THEN _/ ELSE _)  [0, 0, 61] 61) |
  Awhile assn2 bexp acom  (({_}/ WHILE _/ DO _)  [0, 0, 61] 61) 
    
notation com.SKIP (SKIP)
  
fun strip :: "acom  com" where
"strip SKIP = SKIP" |
"strip (x ::= a) = (x ::= a)" |
"strip (C1;; C2) = (strip C1;; strip C2)" |
"strip (IF b THEN C1 ELSE C2) = (IF b THEN strip C1 ELSE strip C2)" |
"strip ({_} WHILE b DO C) = (WHILE b DO strip C)"  


fun pre :: "acom  assn2  assn2" where
"pre SKIP Q = ($1 ** Q)" |
"pre (x ::= a) Q = ((λ(ps,t). xdom ps  vars a  dom ps  Q (ps(x(paval a ps)),t) ) ** $1)" |
"pre (C1;; C2) Q = pre C1 (pre C2 Q)" |
"pre (IF b THEN C1 ELSE C2) Q = (
   $1 **  (λ(ps,n). vars b  dom ps  (if pbval b ps then pre C1 Q (ps,n)  else pre C2 Q (ps,n) )))" |
"pre ({I} WHILE b DO C) Q = (I ** $1)"  
  
  
fun vc :: "acom  assn2  bool" where
"vc SKIP Q = True" |
"vc (x ::= a) Q = True" |
"vc (C1 ;; C2) Q = ((vc C1 (pre C2 Q))  (vc C2 Q) )" |
"vc (IF b THEN C1 ELSE C2) Q = (vc C1 Q  vc C2 Q)" |  
"vc ({I} WHILE b DO C) Q =  ( (s. (I s  vars b  dom (fst s) )  ((λ(s,n). I (s,n)  lmaps_to_axpr b True s) s  pre C (I ** $ 1) s)
          ( (λ(s,n). I (s,n)  lmaps_to_axpr b False s) s  Q s))  vc C (I  ** $ 1))" 

 
lemma dollar0_left: "($ 0 ∧* Q) = Q"  
 apply rule unfolding dollar_def sep_conj_def  
  by force
  
lemma vc_sound: "vc C Q   3' {pre C Q} strip C { Q }"
proof (induct C arbitrary: Q)
  case Askip
  then show ?case
    apply simp
    apply(rule conseqS[OF Frame[OF Skip]])
        by (auto simp: dollar0_left)  
next
  case (Aassign x1 x2)
  then show ?case 
    apply simp
    apply(rule conseqS)
      apply(rule Assign4)
      apply auto done
next
  case (Aseq C1 C2)
  then show ?case   apply (auto intro: Seq)  done
next
  case (Aif b C1 C2)
  then have Aif1: "3' {pre C1 Q} strip C1 {Q}"
        and Aif2: "3' {pre C2 Q} strip C2 {Q}"  by auto
  show ?case apply simp
    apply (rule conseqS) 
      apply(rule If[where P="%(ps,n).  (if pbval b ps then pre C1 Q (ps,n) else pre C2 Q (ps,n))" and Q="Q"])
    subgoal apply simp
      apply (rule conseqS) apply(fact Aif1) by auto 
    subgoal apply simp
      apply (rule conseqS) apply(fact Aif2) by auto 
     apply (auto simp: sep_conj_ac) 
    unfolding sep_conj_def by blast 
next
  case (Awhile I b C)
  then have
       dom : "s. (I s  vars b  dom (fst s) )"
      and i: "s.  (λ(s,n). I (s,n)  lmaps_to_axpr b True s) s  pre C (I ** $ 1) s"
      and ii: "s.  (λ(s,n). I (s,n)  lmaps_to_axpr b False s) s  Q s"
      and C: "3' {pre C (I ** $ 1)} strip C {I ** $ 1}"
     by fastforce+
    
  show ?case
    apply simp 
    apply(rule conseqS)
       apply(rule While[where P=I])
       apply(rule conseqS)
        apply(rule C)
    subgoal using i by auto
    subgoal apply simp using dom unfolding sep_conj_def by force
    subgoal apply simp using dom unfolding sep_conj_def by force
    subgoal using ii apply auto done
    done
qed  
  
lemma vc2valid: "vc C Q  s. P s  pre C Q s  3' {P} strip C { Q}"
  using hoareT_sound2_part weakenpre vc_sound by metis

lemma pre_mono: assumes "s. P s  Q s" shows "s. pre C P s  pre C Q s"   
using assms proof(induct C arbitrary: P Q)
  case Askip
  then show ?case  apply (auto simp: sep_conj_def dollar_def)
    by force
next
  case (Aassign x1 x2)
  then show ?case by (auto simp: sep_conj_def dollar_def)
next
  case (Aseq C1 C2)
  then show ?case by auto
next
  case (Aif b C1 C2)
  then show ?case apply (auto simp: sep_conj_def dollar_def) 
    subgoal for ps n
      apply(rule exI[where x=0]) 
      apply(rule exI[where x=1])
      apply(rule exI[where x=ps]) by auto
    done
next
  case (Awhile x1 x2 C)
  then show ?case by auto
qed
  
lemma vc_mono: assumes "s. P s  Q s" shows "vc C P  vc C Q"        
using assms proof(induct C arbitrary: P Q)
  case Askip
  then show ?case by auto
next
  case (Aassign x1 x2)
  then show ?case  by auto
next
  case (Aseq C1 C2 P Q)
  then have i: "vc C1 (pre C2 P)" and ii: "vc C2 P" by auto
  from  pre_mono[OF ] Aseq(4) have iii: "s. pre C2 P s  pre C2 Q s" by blast
  show ?case  apply auto
      using Aseq(1)[OF i  iii] Aseq(2)[OF ii Aseq(4)] by auto
next
  case (Aif x1 C1 C2)
  then show ?case  by auto
next
  case (Awhile I b C P Q)
  then show ?case by auto
qed


lemma vc_sound': "vc C Q  (s n. P' (s, n)  pre C Q (s, k * n))  (s n. Q (s, n)  Q' (s, n div k))  0 < k  3' {P'} strip C { Q'}"
  using conseq vc_mono vc_sound by metis


  
  
        
lemma pre_Frame: "(s. P s  pre C Q s)  vc C Q
      (C'. strip C = strip C'   vc C' (Q ** F)  (s. (P ** F) s  pre C' (Q ** F) s) )"  
proof (induct C arbitrary: P Q)
  case Askip
  show ?case 
  proof (rule exI[where x="Askip"], safe)
    fix a b
    assume "(P ∧* F) (a, b)"
    then obtain ps1 ps2 n1 n2 where A: "ps1##ps2" "a=ps1+ps2" "b=n1+n2"
      and P: "P (ps1,n1)" and F: "F (ps2,n2)" unfolding sep_conj_def by auto
    from P Askip have p: "($ (Suc 0) ∧* Q) (ps1, n1)" by auto
    
    from p A F
    have "(($ (Suc 0) ∧* Q) ∧* F) (a, b)"
      apply(subst (2) sep_conj_def) by auto
    then show "pre SKIP (Q ∧* F) (a, b)" by (simp add: sep_conj_ac)
  qed simp
next
  case (Aassign x a)
  show ?case 
  proof (rule exI[where x="Aassign x a"], safe)
    fix ps n
    assume "(P ∧* F) (ps,n)"
    then obtain ps1 ps2 n1 n2 where o: "ps1##ps2" "ps=ps1+ps2" "n=n1+n2"
      and P: "P (ps1,n1)" and F: "F (ps2,n2)" unfolding sep_conj_def by auto
    from P Aassign(1) have z: "((λ(ps, t). x  dom ps  vars a  dom ps  Q (ps(x  paval a ps), t))
                                     ∧* $ (Suc 0)) (ps1, n1)" 
        by auto    
    with o F show " pre (x ::= a) (Q ∧* F) (ps,n)" apply auto
      unfolding sep_conj_def dollar_def apply (auto)
        subgoal by(simp add: plus_fun_def)  
        subgoal by(auto simp add: plus_fun_def)  
        subgoal
          by (smt add_update_distrib dom_fun_upd domain_conv insert_dom option.simps(3) paval_extend sep_disj_fun_def)
        done
  qed auto
next
  case (Aseq C1 C2) 
  from Aseq(3) have pre: "s. P s  pre C1 (pre C2 Q) s" by auto
  from Aseq(4) have vc1: "vc C1 (pre C2 Q)" and vc2: "vc C2 Q" by auto
  from Aseq(1)[OF pre vc1] obtain C1' where S1: "strip C1 = strip C1'"
      and vc1': "vc C1' (pre C2 Q ∧* F)"
      and I1: "(s. (P ∧* F) s  pre C1' (pre C2 Q ∧* F) s)" by blast
  from Aseq(2)[of "pre C2 Q" Q, OF _ vc2] obtain C2' where S2: "strip C2 = strip C2'"
      and vc2': "vc C2' (Q ∧* F)"
      and I2: "(s. (pre C2 Q ∧* F) s  pre C2' (Q ∧* F) s) " by blast
   
  show ?case apply(rule exI[where x="Aseq C1' C2'"])    
    apply safe
    subgoal using S1 S2 by auto
    subgoal apply simp apply safe
      subgoal using vc_mono[OF I2 vc1'] .
      subgoal by (fact vc2')
    done
    subgoal using I1 I2 pre_mono
      by force 
    done
next
  case (Aif b C1 C2)
  from Aif(3) have i: "s. P s 
          ($ (Suc 0) ∧*
           (λ(ps, n). vars b  dom ps  (if pbval b ps then pre C1 Q (ps, n) else pre C2 Q (ps, n))))
           s" by simp  
  from Aif(4) have vc1: "vc C1 Q" and vc2: "vc C2 Q" by auto 
  from Aif(1)[where P="pre C1 Q" and Q="Q", OF _ vc1] obtain C1' where
    s1: "strip C1 = strip C1'" and v1: "vc C1' (Q ∧* F)"
    and p1: "(s. (pre C1 Q ∧* F) s  pre C1' (Q ∧* F) s)"
    by auto
  from Aif(2)[where P="pre C2 Q" and Q="Q", OF _ vc2] obtain C2' where
    s2: "strip C2 = strip C2'" and v2: "vc C2' (Q ∧* F)" 
    and p2: "(s. (pre C2 Q ∧* F) s  pre C2' (Q ∧* F) s)"
    by auto
    
  show ?case apply(rule exI[where x="Aif b C1' C2'"])
  proof safe
    fix ps n
    assume "(P ∧* F) (ps, n)"
    then obtain ps1 ps2 n1 n2 where o: "ps1##ps2" "ps=ps1+ps2" "n=n1+n2"
      and P: "P (ps1,n1)" and F: "F (ps2,n2)" unfolding sep_conj_def by auto
    from P i have P': "($ (Suc 0) ∧*
         (λ(ps, n). vars b  dom ps  (if pbval b ps then pre C1 Q (ps, n) else pre C2 Q (ps, n))))
         (ps1,n1)" by auto
    have PF: "(($ (Suc 0) ∧*
         (λ(ps, n). vars b  dom ps  (if pbval b ps then pre C1 Q (ps, n) else pre C2 Q (ps, n)))) ** F)
         (ps,n)" apply(subst (2) sep_conj_def)
        apply(rule exI[where x="(ps1,n1)"])
        apply(rule exI[where x="(ps2,n2)"])
      using F P' o by auto 
    from this[simplified sep_conj_assoc] obtain ps1 ps2 n1 n2 where o: "ps1##ps2" "ps=ps1+ps2" "n=n1+n2"
      and P: "($ (Suc 0)) (ps1,n1)" and F: "((λ(ps, n). vars b  dom ps  (if pbval b ps then pre C1 Q (ps, n) else pre C2 Q (ps, n))) ∧* F) (ps2,n2)"
      unfolding sep_conj_def apply auto by fast
    then have "((λ(ps, n). vars b  dom ps  (if pbval b ps then (pre C1 Q  ∧* F) (ps, n) else (pre C2 Q  ∧* F) (ps, n)))) (ps2,n2)"    
      unfolding sep_conj_def apply auto
      apply (metis contra_subsetD domD map_add_dom_app_simps(1) plus_fun_conv sep_add_commute)
      using pbval_extend apply auto[1]                                                     
      apply (metis contra_subsetD domD map_add_dom_app_simps(1) plus_fun_conv sep_add_commute) 
      using pbval_extend apply auto[1]    done
    then have "((λ(ps, n). vars b  dom ps  (if pbval b ps then (pre C1' (Q ∧* F)) (ps, n) else (pre C2' (Q ∧* F)) (ps, n)))) (ps2,n2)" 
      using p1 p2  by auto
    with o P 
    show "pre (IF b THEN C1' ELSE C2') (Q ∧* F) (ps, n)"
      apply auto apply(subst sep_conj_def) by force
  qed (auto simp: s1 s2 v1 v2)
next
  case (Awhile I b C)
  from Awhile(2) have pre: "s. P s   (I ** $1) s"  by auto
  from Awhile(3) have 
    dom:  "ps n. I (ps, n)  vars b  dom ps" 
  and  tB: "s. I s  vars b  dom (fst s)  pbval b (fst s)  pre C (I ∧* $ (Suc 0)) s"
  and  fB: "ps n. I (ps, n)  vars b  dom ps  ¬ pbval b ps  Q (ps, n)"
  and vcB: "vc C (I ∧* $(Suc 0))" by auto
  from Awhile(1)[OF tB vcB] obtain C' where st: "strip C = strip C'"
    and vc': "vc C' ((I ∧* $ (Suc 0)) ∧* F)"
    and pre': "(s. ((λa. I a  vars b  dom (fst a)  pbval b (fst a)) ∧* F) s 
            pre C' ((I ∧* $ (Suc 0)) ∧* F) s)"
    by auto
  show ?case apply(rule exI[where x="Awhile (I**F) b C'"])
    apply safe
    subgoal using st by simp 
    subgoal apply simp apply safe
        subgoal using dom unfolding sep_conj_def apply auto
          by (metis domD sep_substate_disj_add subState subsetCE) 
        subgoal  using pre' apply(auto simp: sep_conj_ac) 
            apply(subst (asm)  sep_conj_def)
            apply(subst (asm)  sep_conj_def) apply auto
          by (metis dom pbval_extend sep_add_commute sep_disj_commuteI)
        subgoal using fB unfolding sep_conj_def apply auto
          using dom pbval_extend by fastforce
        subgoal using vc' apply(auto simp: sep_conj_ac) done
        done
      subgoal apply simp using pre unfolding sep_conj_def apply auto
        by (smt semiring_normalization_rules(23) sep_add_assoc sep_add_commute sep_add_disjD sep_add_disjI1)
      done
qed

  
  
        
        
        
lemma vc_complete: "3a {P} c { Q }  (C. vc C Q  (s. P s  pre C Q s)  strip C = c)"
proof(induct   rule: hoare3a.induct)
  case Skip
  then show ?case apply(rule exI[where x="Askip"]) by auto
next
  case (Assign4 x a Q)
  then show ?case apply(rule exI[where x="Aassign x a"]) by auto
next
  case (If P b c1 Q c2)
  from If(2) obtain C1 where A1: "vc C1 Q" "strip C1 = c1" and 
    A2: "ps n. (P (ps, n)  lmaps_to_axpr b True ps)  pre C1 Q (ps,n)"
    by blast
  from If(4) obtain C2 where B1: "vc C2 Q" "strip C2 = c2" and B2:
    "ps n. (P (ps, n)  lmaps_to_axpr b False ps)  pre C2 Q (ps,n)"
    by blast
      
  show ?case apply(rule exI[where x="Aif b C1 C2"]) using A1 B1 apply auto
    subgoal for ps n
      unfolding sep_conj_def dollar_def apply auto
      apply(rule exI[where x="0"])
      apply(rule exI[where x="1"])
      apply(rule exI[where x="ps"])
      using A2 B2 by auto
  done
next
  case (Frame P C Q F) 
  then obtain C' where vc: "vc C' Q" and pre: "(s. P s  pre C' Q s)"
      and strip: "strip C' = C" by auto 
  show ?case using pre_Frame[OF pre vc] strip by metis
next
  case (Seq P c1 Q c2 R)
  from Seq(2) obtain C1 where A1: "vc C1 Q" "strip C1 = c1" and 
    A2: "s. P s  pre C1 Q s"
    by blast
  from Seq(4) obtain C2 where B1: "vc C2 R" "strip C2 = c2" and 
    B2: "s. Q s  pre C2 R s"
    by blast
  show ?case apply(rule exI[where x="Aseq C1 C2"])
    using B1 A1 apply auto
    subgoal using vc_mono B2 by auto
    subgoal apply(rule pre_mono[where P=Q])  using  B2 apply auto
      using A2 by auto
    done
next
  case (While I b c)
  then obtain C where 1: "vc C ((λ(s, n). I (s, n)  vars b  dom s) ∧* $ 1)"
          "strip C = c" and 2:
         "ps n. (I (ps, n)  lmaps_to_axpr b True ps) 
              pre C ((λ(s, n). I (s, n)  vars b  dom s) ∧* $ 1) (ps,n) " by blast
    
  show ?case apply(rule exI[where x="Awhile (λ(s, n). I (s, n)  vars b  dom s) b C"])
    using 1 2 by auto 
next
  case (conseqS P c Q P' Q')
  then obtain C' where C': "vc C' Q" "(s. P s  pre C' Q s)" "strip C' = c"
    by blast
  show ?case apply(rule exI[where x=C'])
      using C' conseqS(3,4) pre_mono vc_mono by force
qed 
           
   
  
  
theorem vc_completeness:
  assumes "3' {P} c { Q}"
  shows "C k. vc C (Q ** sep_true)
           (ps n. P (ps, n)  pre C (λ(ps, n). (Q ** sep_true) (ps, n div k)) (ps, k * n))
           strip C = c"
proof - 
  let ?QG = "λk (ps,n). (Q ** sep_true) (ps,n div k)"
  from assms obtain k where k[simp]: "k>0" and p: "ps n. P (ps, n)  wp3' c (λ(ps, n). (Q ** sep_true) (ps, n div k)) (ps, k * n)" 
    using valid_wp by blast 
      
  from wpT_is_pre  have R: "3a {wp3' c (?QG k)} c {?QG k}" by auto
  
  have z: "(s. (λ(ps, n). (Q ∧* (λs. True)) (ps, n div k)) s)  (s. (λ(ps, n). (Q ∧* (λs. True)) (ps, n)) s)"
    by (metis (no_types) case_prod_conv k neq0_conv nonzero_mult_div_cancel_left old.prod.exhaust)
  
     
  have z: "ps n. ((Q ∧* (λs. True)) (ps, n div k)  (Q ∧* (λs. True)) (ps, n))"   
  proof -
    fix ps n
    assume "(Q ∧* (λs. True)) (ps, n div k) "
    then obtain ps1 n1 ps2 n2
      where o: "ps1 ## ps2" "ps = ps1 + ps2" "Q (ps1, n1)" "n div k = n1 + n2"
      unfolding sep_conj_def by auto
    from o(4) have nn1: "nn1" using k
      by (metis (full_types) add_leE div_le_dividend) 
    show "(Q ∧* (λs. True)) (ps, n)" unfolding sep_conj_def
        apply(rule exI[where x="(ps1, n1)"])
      apply(rule exI[where x="(ps2, n - n1)"])
      using o nn1 by auto   
  qed
  then have z': "s. ((Q ∧* (λs. True)) (fst s, (snd s) div k)  (Q ∧* (λs. True)) s)"
    by (metis prod.collapse)   
      
  from vc_complete[OF R] obtain C
    where o: "vc C (λ(ps, n). (Q ∧* (λs. True)) (ps, n div k))"
      "a b. wp3' (strip C) (λ(ps, n). (Q ∧* (λs. True)) (ps, n div k)) (a, b) 
          pre C (λ(ps, n). (Q ∧* (λs. True)) (ps, n div k)) (a, b)"
      "c = strip C" by auto
    
  have y: "ps n. P (ps, n)   pre C (λ(ps, n). (Q ∧* (λs. True)) (ps, n div k)) (ps, k * n)"
    using o p by metis 
    
  show ?thesis apply(rule exI[where x=C])  apply(rule exI[where x=k])
    apply safe
    subgoal apply(rule vc_mono[OF _ o(1)]) using z  by blast
    subgoal using y by blast
    subgoal using o by simp
    done
qed

end