Theory utp_hoare

section ‹ Relational Hoare calculus ›

theory utp_hoare
  imports 
    utp_rel_laws
    utp_theory
begin

subsection ‹ Hoare Triple Definitions and Tactics ›

definition hoare_r :: " cond   hrel   cond  bool" ("_/ _/ _u") where
"pQru = ((p<  r>)  Q)"

declare hoare_r_def [upred_defs]

named_theorems hoare and hoare_safe

method hoare_split uses hr = 
  ((simp add: assigns_comp)?, ― ‹ Combine Assignments where possible ›
   (auto
    intro: hoare intro!: hoare_safe hr
    simp add: conj_comm conj_assoc usubst unrest))[1] ― ‹ Apply Hoare logic laws ›

method hoare_auto uses hr = (hoare_split hr: hr; (rel_simp)?, auto?)

subsection ‹ Basic Laws ›

lemma hoare_meaning:
  "PSQu = ( s s'. Pe s  Se (s, s')  Qe s')"
  by (rel_auto)

lemma hoare_assume: "PSQu  ?[P] ;; S = ?[P] ;; S ;; ?[Q]"
  by (rel_auto)

lemma hoare_r_conj [hoare_safe]: " pQru; pQsu   pQr  su"
  by rel_auto

lemma hoare_r_weaken_pre [hoare]:
  "pQru  p  qQru"
  "qQru  p  qQru"
  by rel_auto+

lemma pre_str_hoare_r:
  assumes "`p1  p2`" and "p2Cqu"
  shows "p1Cqu" 
  using assms by rel_auto
    
lemma post_weak_hoare_r:
  assumes "pCq2u" and "`q2  q1`"
  shows "pCq1u" 
  using assms by rel_auto

lemma hoare_r_conseq: " `p1  p2`; p2Sq2u; `q2  q1`   p1Sq1u"
  by rel_auto

subsection ‹ Assignment Laws ›

lemma assigns_hoare_r [hoare_safe]: "`p  σ  q`  pσaqu"
  by rel_auto

lemma assigns_backward_hoare_r: 
  "σ  pσapu"
  by rel_auto

lemma assign_floyd_hoare_r:
  assumes "vwb_lens x"
  shows "p assign_r x e v  p«v»/x  &x =u e«v»/xu"
  using assms
  by (rel_auto, metis vwb_lens_wb wb_lens.get_put)

lemma assigns_init_hoare [hoare_safe]:
  " vwb_lens x; x  p; x  v; &x =u v  pSqu   px := v ;; Squ"
  by (rel_auto)

lemma skip_hoare_r [hoare_safe]: "pIIpu"
  by rel_auto

lemma skip_hoare_impl_r [hoare_safe]: "`p  q`  pIIqu"
  by rel_auto  

subsection ‹ Sequence Laws ›

lemma seq_hoare_r: " pQ1su ; sQ2ru   pQ1 ;; Q2ru"
  by rel_auto

lemma seq_hoare_invariant [hoare_safe]: " pQ1pu ; pQ2pu   pQ1 ;; Q2pu"
  by rel_auto

lemma seq_hoare_stronger_pre_1 [hoare_safe]: 
  " p  qQ1p  qu ; p  qQ2qu   p  qQ1 ;; Q2qu"
  by rel_auto

lemma seq_hoare_stronger_pre_2 [hoare_safe]: 
  " p  qQ1p  qu ; p  qQ2pu   p  qQ1 ;; Q2pu"
  by rel_auto
    
lemma seq_hoare_inv_r_2 [hoare]: " pQ1qu ; qQ2qu   pQ1 ;; Q2qu"
  by rel_auto

lemma seq_hoare_inv_r_3 [hoare]: " pQ1pu ; pQ2qu   pQ1 ;; Q2qu"
  by rel_auto

subsection ‹ Conditional Laws ›

lemma cond_hoare_r [hoare_safe]: " b  pSqu ; ¬b  pTqu   pS  b r Tqu"
  by rel_auto

lemma cond_hoare_r_wp: 
  assumes "p'Squ" and "p''Tqu"
  shows "(b  p')  (¬b  p'')S  b r Tqu"
  using assms by pred_simp

lemma cond_hoare_r_sp:
  assumes b  pSqu and ¬b  pTsu
  shows pS  b r Tq  su
  using assms by pred_simp

subsection ‹ Recursion Laws ›

lemma nu_hoare_r_partial: 
  assumes induct_step:
    " st P. pPqu  pF Pqu"   
  shows "pν F qu"  
  by (meson hoare_r_def induct_step lfp_lowerbound order_refl)

lemma mu_hoare_r:
  assumes WF: "wf R"
  assumes M:"mono F"  
  assumes induct_step:
    " st P. p  (e,«st»)u u «R»Pqu  p  e =u «st»F Pqu"   
  shows "pμ F qu"  
  unfolding hoare_r_def
proof (rule mu_rec_total_utp_rule[OF WF M , of _ e ], goal_cases)
  case (1 st)
  then show ?case 
    using induct_step[unfolded hoare_r_def, of "(p<  (e<, «st»)u u «R»  q>)" st]
    by (simp add: alpha)    
qed
    
lemma mu_hoare_r':
  assumes WF: "wf R"
  assumes M:"mono F"  
  assumes induct_step:
    " st P. p  (e,«st»)u u «R» P qu  p  e =u «st» F P qu" 
  assumes I0: "`p'  p`"  
  shows "p' μ F qu"
  by (meson I0 M WF induct_step mu_hoare_r pre_str_hoare_r)

subsection ‹ Iteration Rules ›

lemma iter_hoare_r: "PSPu  PSPu"
  by (rel_simp', metis (mono_tags, lifting) mem_Collect_eq rtrancl_induct)

lemma while_hoare_r [hoare_safe]:
  assumes "p  bSpu"
  shows "pwhile b do S od¬b  pu"
  using assms
  by (simp add: while_top_def hoare_r_def, rule_tac lfp_lowerbound) (rel_auto)

lemma while_invr_hoare_r [hoare_safe]:
  assumes "p  bSpu" "`pre  p`" "`(¬b  p)  post`"
  shows "prewhile b invr p do S odpostu"
  by (metis assms hoare_r_conseq while_hoare_r while_inv_def)

lemma while_r_minimal_partial:
  assumes seq_step: "`p  invar`"
  assumes induct_step: "invar b C invaru"  
  shows "pwhile b do C od¬b  invaru"
  using induct_step pre_str_hoare_r seq_step while_hoare_r by blast

lemma approx_chain: 
  "(n::nat. p  v <u «n»<) = p<"
  by (rel_auto)

text ‹ Total correctness law for Hoare logic, based on constructive chains. This is limited to
  variants that have naturals numbers as their range. ›
    
lemma while_term_hoare_r:
  assumes " z::nat. p  b  v =u «z»Sp  v <u «z»u"
  shows "pwhile b do S od¬b  pu"
proof -
  have "(p<  ¬ b  p>)  (μ X  S ;; X  b r II)"
  proof (rule mu_refine_intro)

    from assms show "(p<  ¬ b  p>)  S ;; (p<  ¬ b  p>)  b r II"
      by (rel_auto)

    let ?E = "λ n. p  v <u «n»<"
    show "(p<  (μ X  S ;; X  b r II)) = (p<  (ν X  S ;; X  b r II))"
    proof (rule constr_fp_uniq[where E="?E"])

      show "(n. ?E(n)) = p<"
        by (rel_auto)
          
      show "mono (λX. S ;; X  b r II)"
        by (simp add: cond_mono monoI seqr_mono)
          
      show "constr (λX. S ;; X  b r II) ?E"
      proof (rule constrI)
        
        show "chain ?E"
        proof (rule chainI)
          show "p  v <u «0»< = false"
            by (rel_auto)
          show "i. p  v <u «Suc i»<  p  v <u «i»<"
            by (rel_auto)
        qed
          
        from assms
        show "X n. (S ;; X  b r II  p  v <u «n + 1»<) =
                     (S ;; (X  p  v <u «n»<)  b r II  p  v <u «n + 1»<)"
          apply (rel_auto)
          using less_antisym less_trans apply blast
          done
      qed  
    qed
  qed

  thus ?thesis
    by (simp add: hoare_r_def while_bot_def)
qed

lemma while_vrt_hoare_r [hoare_safe]:
  assumes " z::nat. p  b  v =u «z»Sp  v <u «z»u" "`pre  p`" "`(¬b  p)  post`"
  shows "prewhile b invr p vrt v do S odpostu"
  apply (rule hoare_r_conseq[OF assms(2) _ assms(3)])
  apply (simp add: while_vrt_def)
  apply (rule while_term_hoare_r[where v="v", OF assms(1)]) 
  done
  
text ‹ General total correctness law based on well-founded induction ›
        
lemma while_wf_hoare_r:
  assumes WF: "wf R"
  assumes I0: "`pre  p`"
  assumes induct_step:" st. b  p  e =u «st»Qp  (e, «st»)u u «R»u"
  assumes PHI:"`(¬b  p)  post`"  
  shows "prewhile b invr p do Q odpostu"
unfolding hoare_r_def while_inv_bot_def while_bot_def
proof (rule pre_weak_rel[of _ "p<" ])
  from I0 show "`pre<  p<`"
    by rel_auto
  show "(p<  post>)  (μ X  Q ;; X  b r II)"
  proof (rule mu_rec_total_utp_rule[where e=e, OF WF])
    show "Monotonic (λX. Q ;; X  b r II)"
      by (simp add: closure)
    have induct_step': " st. (b  p   e =u «st» <  (p  (e,«st»)u u «R» > ))  Q"
      using induct_step by rel_auto  
    with PHI
    show "st. (p<  e< =u «st»  post>)  Q ;; (p<  (e<, «st»)u u «R»  post>)  b r II" 
      by (rel_auto)
  qed       
qed

subsection ‹ Frame Rules ›

text ‹ Frame rule: If starting $S$ in a state satisfying $p establishes q$ in the final state, then
  we can insert an invariant predicate $r$ when $S$ is framed by $a$, provided that $r$ does not
  refer to variables in the frame, and $q$ does not refer to variables outside the frame. ›

lemma frame_hoare_r:
  assumes "vwb_lens a" "a  r" "a  q" "pPqu"  
  shows "p  ra:[P]q  ru"
  using assms
  by (rel_auto, metis)

lemma frame_strong_hoare_r [hoare_safe]: 
  assumes "vwb_lens a" "a  r" "a  q" "p  rSqu"
  shows "p  ra:[S]q  ru"
  using assms by (rel_auto, metis)

lemma frame_hoare_r' [hoare_safe]: 
  assumes "vwb_lens a" "a  r" "a  q" "r  pSqu"
  shows "r  pa:[S]r  qu"
  using assms
  by (simp add: frame_strong_hoare_r utp_pred_laws.inf.commute)

lemma antiframe_hoare_r:
  assumes "vwb_lens a" "a  r" "a  q" "pPqu"  
  shows "p  r a:⟦P q  ru"
  using assms by (rel_auto, metis)
    
lemma antiframe_strong_hoare_r:
  assumes "vwb_lens a" "a  r" "a  q" "p  rPqu"  
  shows "p  r a:⟦P q  ru"
  using assms by (rel_auto, metis)
  
end