Theory VTcomp
theory VTcomp
  imports Exc_Nres_Monad
begin
section ‹Library›
text ‹
This theory contains a collection of auxiliary material that was used as a library for the contest.
›
lemma monadic_WHILEIT_unfold:
  "monadic_WHILEIT I b f s = do {
    ASSERT (I s); bb←b s; if bb then do { s ← f s; monadic_WHILEIT I b f s } else RETURN s
  }"      
  unfolding monadic_WHILEIT_def
  apply (subst RECT_unfold)
  apply refine_mono
  by simp
no_notation Ref.lookup (‹!_› 61)
no_notation Ref.update (‹_ := _› 62)
subsection ‹Specialized Rules for Foreach-Loops›
lemma nfoldli_upt_rule:
  assumes INTV: "lb≤ub"
  assumes I0: "I lb σ0"
  assumes IS: "⋀i σ. ⟦ lb≤i; i<ub; I i σ; c σ ⟧ ⟹ f i σ ≤ SPEC (I (i+1))"
  assumes FNC: "⋀i σ. ⟦ lb≤i; i≤ub; I i σ; ¬c σ ⟧ ⟹ P σ"
  assumes FC: "⋀σ. ⟦ I ub σ; c σ ⟧ ⟹ P σ"
  shows "nfoldli [lb..<ub] c f σ0 ≤ SPEC P"
  apply (rule nfoldli_rule[where I="λl _ σ. I (lb+length l) σ"])
  apply simp_all
  apply (simp add: I0)
  subgoal using IS
    by (metis Suc_eq_plus1 add_diff_cancel_left' eq_diff_iff le_add1 length_upt upt_eq_lel_conv)
  subgoal for l1 l2 σ 
    apply (rule FNC[where i="lb + length l1"])
    apply (auto simp: INTV)
    using INTV upt_eq_append_conv by auto
  apply (rule FC) using INTV 
  by auto  
definition [enres_unfolds]: "efor (lb::int) ub f σ ≡ doE {
  EASSERT (lb≤ub);
  (_,σ) ← EWHILET (λ(i,σ). i<ub) (λ(i,σ). doE { σ ← f i σ; ERETURN (i+1,σ) }) (lb,σ);
  ERETURN σ
}"  
  
lemma efor_rule:
  assumes INTV: "lb≤ub"
  assumes I0: "I lb σ0"
  assumes IS: "⋀i σ. ⟦ lb≤i; i<ub; I i σ ⟧ ⟹ f i σ ≤ ESPEC E (I (i+1))"
  assumes FC: "⋀σ. ⟦ I ub σ ⟧ ⟹ P σ"
  shows "efor lb ub f σ0 ≤ ESPEC E P"
  unfolding efor_def
  supply EWHILET_rule[where R="measure (λ(i,_). nat (ub-i))" and I="λ(i,σ). lb≤i ∧ i≤ub ∧ I i σ", refine_vcg]
  apply refine_vcg
  apply auto
  using assms apply auto
  done
  
  
subsection ‹Improved Do-Notation for the ‹nres›-Monad›  
abbreviation (do_notation) bind_doN where "bind_doN ≡ Refine_Basic.bind"
notation (output) bind_doN (infixl ‹⤜› 54)
notation (ASCII output) bind_doN (infixl ‹>>=› 54)
nonterminal doN_binds and doN_bind
syntax
  "_doN_block" :: "doN_binds ⇒ 'a" (‹doN {//(2  _)//}› [12] 62)
  "_doN_bind"  :: "[pttrn, 'a] ⇒ doN_bind" (‹(2_ ←/ _)› 13)
  "_doN_let" :: "[pttrn, 'a] ⇒ doN_bind" (‹(2let _ =/ _)› [1000, 13] 13)
  "_doN_then" :: "'a ⇒ doN_bind" (‹_› [14] 13)
  "_doN_final" :: "'a ⇒ doN_binds" (‹_›)
  "_doN_cons" :: "[doN_bind, doN_binds] ⇒ doN_binds" (‹_;//_› [13, 12] 12)
  "_thenM" :: "['a, 'b] ⇒ 'c" (infixl ‹⪢› 54)
syntax (ASCII)
  "_doN_bind" :: "[pttrn, 'a] ⇒ doN_bind" (‹(2_ <-/ _)› 13)
  "_thenM" :: "['a, 'b] ⇒ 'c" (infixl ‹>>› 54)
syntax_consts
  "_doN_block" "_doN_bind" "_doN_cons" "_thenM" ⇌ bind_doE and
  "_doN_let" ⇌ Let
translations
  "_doN_block (_doN_cons (_doN_then t) (_doN_final e))"
    ⇌ "CONST bind_doN t (λ_. e)"
  "_doN_block (_doN_cons (_doN_bind p t) (_doN_final e))"
    ⇌ "CONST bind_doN t (λp. e)"
  "_doN_block (_doN_cons (_doN_let p t) bs)"
    ⇌ "let p = t in _doN_block bs"
  "_doN_block (_doN_cons b (_doN_cons c cs))"
    ⇌ "_doN_block (_doN_cons b (_doN_final (_doN_block (_doN_cons c cs))))"
  "_doN_cons (_doN_let p t) (_doN_final s)"
    ⇌ "_doN_final (let p = t in s)"
  "_doN_block (_doN_final e)" ⇀ "e"
  "(m ⪢ n)" ⇀ "(m ⤜ (λ_. n))"
subsection ‹Array Blit exposed to Sepref›  
  definition "op_list_blit src si dst di len ≡ 
    (take di dst @ take len (drop si src) @ drop (di+len) dst)"
  context 
    notes op_list_blit_def[simp] 
  begin  
    sepref_decl_op (no_def) list_blit : 
      "op_list_blit" 
      :: "[λ((((src,si),dst),di),len). si+len ≤ length src ∧ di+len ≤ length dst]⇩f  
        ((((⟨A⟩list_rel ×⇩r nat_rel) ×⇩r ⟨A⟩list_rel) ×⇩r nat_rel) ×⇩r nat_rel) → ⟨A⟩list_rel" .
  end
  lemma blit_len[simp]: "si + len ≤ length src ∧ di + len ≤ length dst 
    ⟹ length (op_list_blit src si dst di len) = length dst"
    by (auto simp: op_list_blit_def)
  
    
  context 
    notes [fcomp_norm_unfold] = array_assn_def[symmetric]
  begin    
    lemma array_blit_hnr_aux: 
          "(uncurry4 (λsrc si dst di len. do { blit src si dst di len; return dst }), 
            uncurry4 mop_list_blit) 
      ∈ is_array⇧k*⇩anat_assn⇧k*⇩ais_array⇧d*⇩anat_assn⇧k*⇩anat_assn⇧k →⇩a is_array"
      apply sepref_to_hoare
      apply (clarsimp simp: refine_pw_simps)
      apply (sep_auto simp: is_array_def op_list_blit_def)
      done
    
    sepref_decl_impl (ismop) array_blit: array_blit_hnr_aux .
  end  
end