Theory Unified_PW_Impl

theory Unified_PW_Impl
  imports Refine_Imperative_HOL.IICF Unified_PW_Hashing Heap_Hash_Map
begin

subsection ‹Imperative Implementation›

text ‹
We now obtain an imperative implementation using the Sepref tool.
We will implement the waiting list as a HOL list and the passed set as an imperative hash map.
›

context notes [split!] = list.split begin
sepref_decl_op list_hdtl: "λ (x # xs)  (x, xs)" :: "[λl. l[]]f Alist_rel  A ×r Alist_rel"
  by auto
end

context Worklist_Map2_Defs
begin

definition trace where
  "trace  λtype a. RETURN ()"

definition
  "explored_string = ''Explored''"

definition
  "final_string = ''Final''"

definition
  "added_string = ''Add''"

definition
  "subsumed_string = ''Subsumed''"

definition
  "empty_string = ''Empty''"

lemma add_pw'_map2_alt_def:
  "add_pw'_map2 passed wait a = do {
   trace explored_string a;
   nfoldli (succs a) (λ(_, _, brk). ¬brk)
    (λa (passed, wait, _).
      do {
      RETURN (
        if empty a then
            (passed, wait, False)
        else if F' a then (passed, wait, True)
        else
          let
            k = key a;
            (v, passed) = op_map_extract k passed
          in
            case v of
              None  (passed(k  {COPY a}), a # wait, False) |
              Some passed' 
                if  x  passed'. a  x then
                  (passed(k  passed'), wait, False)
                else
                  (passed(k  (insert (COPY a) passed')), a # wait, False)
        )
      }
    )
    (passed,wait,False)
  }"
  unfolding add_pw'_map2_def id_def op_map_extract_def trace_def
  apply simp
  apply (fo_rule fun_cong)
  apply (fo_rule arg_cong)
  apply (rule ext)+
  by (auto 4 3 simp: Let_def split: option.split)

  lemma add_pw'_map2_full_trace_def:
  "add_pw'_map2 passed wait a = do {
   trace explored_string a;
   nfoldli (succs a) (λ(_, _, brk). ¬brk)
    (λa (passed, wait, _).
      do {
        if empty a then
            do {trace empty_string a; RETURN (passed, wait, False)}
        else if F' a then do {trace final_string a; RETURN (passed, wait, True)}
        else
          let
            k = key a;
            (v, passed) = op_map_extract k passed
          in
            case v of
              None  do {trace added_string a; RETURN (passed(k  {COPY a}), a # wait, False)} |
              Some passed' 
                if  x  passed'. a  x then
                  do {trace subsumed_string a; RETURN (passed(k  passed'), wait, False)}
                else do {
                    trace added_string a;
                    RETURN (passed(k  (insert (COPY a) passed')), a # wait, False)
                  }
      }
    )
    (passed,wait,False)
  }"
    unfolding add_pw'_map2_alt_def
    unfolding trace_def
    apply (simp add:)
    apply (fo_rule fun_cong)
    apply (fo_rule arg_cong)
    apply (rule ext)+
    apply (auto simp add: Let_def split: option.split)
    done

end

locale Worklist_Map2_Impl =
   Worklist4_Impl + Worklist_Map2_Impl_Defs + Worklist_Map2 +
  fixes K
  assumes [sepref_fr_rules]: "(keyi,RETURN o PR_CONST key)  Ak a K"
  assumes [sepref_fr_rules]: "(copyi, RETURN o COPY)  Ak a A"
  assumes [sepref_fr_rules]: "(uncurry tracei,uncurry trace)  id_assnk *a Ak a id_assn"
  assumes pure_K: "is_pure K"
  assumes left_unique_K: "IS_LEFT_UNIQUE (the_pure K)"
  assumes right_unique_K: "IS_RIGHT_UNIQUE (the_pure K)"
begin
  sepref_register
    "PR_CONST a0" "PR_CONST F'" "PR_CONST (⊴)" "PR_CONST succs" "PR_CONST empty" "PR_CONST key"
    "PR_CONST F" trace

  lemma [def_pat_rules]:
    "a0  UNPROTECT a0" "F'  UNPROTECT F'" "(⊴)  UNPROTECT (⊴)" "succs  UNPROTECT succs"
    "empty  UNPROTECT empty" "keyi  UNPROTECT keyi" "F  UNPROTECT F" "key  UNPROTECT key"
    by simp_all

  lemma take_from_list_alt_def:
    "take_from_list xs = do {_  ASSERT (xs  []); RETURN (hd_tl xs)}"
    unfolding take_from_list_def by (auto simp: pw_eq_iff refine_pw_simps)

  lemma [safe_constraint_rules]: "CN_FALSE is_pure A  is_pure A" by simp

  lemmas [sepref_fr_rules] = hd_tl_hnr

  lemmas [safe_constraint_rules] = pure_K left_unique_K right_unique_K

  lemma [sepref_import_param]:
    "(explored_string, explored_string)  Id"
    "(subsumed_string, subsumed_string)  Id"
    "(added_string, added_string)  Id"
    "(final_string, final_string)  Id"
    "(empty_string, empty_string)  Id"
    unfolding
      explored_string_def subsumed_string_def added_string_def final_string_def empty_string_def
    by simp+
  
  lemmas [sepref_opt_simps] =
    explored_string_def
    subsumed_string_def
    added_string_def
    final_string_def
    empty_string_def

  sepref_thm pw_algo_map2_impl is
    "uncurry0 (do {(r, p)  pw_algo_map2; RETURN r})" :: "unit_assnk a bool_assn"
    unfolding pw_algo_map2_def add_pw'_map2_full_trace_def PR_CONST_def TRACE'_def[symmetric]
    supply [[goals_limit = 1]]
    supply conv_to_is_Nil[simp]
    unfolding fold_lso_bex
    unfolding take_from_list_alt_def
    apply (rewrite in "{a0}" lso_fold_custom_empty)
    unfolding hm.hms_fold_custom_empty
    apply (rewrite in "[a0]" HOL_list.fold_custom_empty)
     apply (rewrite in "{}" lso_fold_custom_empty)
    unfolding F_split
    by sepref

  concrete_definition (in -) pw_impl
  for Lei a0i Fi succsi emptyi
  uses Worklist_Map2_Impl.pw_algo_map2_impl.refine_raw is "(uncurry0 ?f,_)_"

end ― ‹Worklist Map2 Impl›

locale Worklist_Map2_Impl_finite = Worklist_Map2_Impl + Worklist_Map2_finite
begin

lemma pw_algo_map2_correct':
  "(do {(r, p)  pw_algo_map2; RETURN r})  SPEC (λbrk. brk = F_reachable)"
  using pw_algo_map2_correct
  apply clarsimp
  apply (cases pw_algo_map2)
   apply (solves simp)
  unfolding RETURN_def
  apply clarsimp
    subgoal for X
    apply (cases "do {(r, p)  RES X; RES {r}}")
       apply (subst (asm) Refine_Basic.bind_def, force)
      subgoal premises prems for X'
      proof -
        have "r = F_reachable" if "(r, p)  X" for r p
          using that prems(1) by auto
        then show ?thesis
          by (auto simp: pw_le_iff refine_pw_simps)
      qed
      done
    done

lemma pw_impl_hnr_F_reachable:
  "(uncurry0 (pw_impl keyi copyi tracei Lei a0i Fi succsi emptyi), uncurry0 (RETURN F_reachable))
   unit_assnk a bool_assn"
  using
    pw_impl.refine[
      OF Worklist_Map2_Impl_axioms,
      FCOMP pw_algo_map2_correct'[THEN Id_SPEC_refine, THEN nres_relI]
      ]
  by (simp add: RETURN_def)

end

locale Worklist_Map2_Hashable =
  Worklist_Map2_Impl_finite
begin

  sepref_decl_op F_reachable :: "bool_rel" .
  lemma [def_pat_rules]: "F_reachable  op_F_reachable" by simp


  lemma hnr_op_F_reachable:
    assumes "GEN_ALGO a0i (λa0i. (uncurry0 a0i, uncurry0 (RETURN a0))  unit_assnk a A)"
    assumes "GEN_ALGO Fi (λFi. (Fi,RETURN o F')  Ak a bool_assn)"
    assumes "GEN_ALGO Lei (λLei. (uncurry Lei,uncurry (RETURN oo (⊴)))  Ak *a Ak a bool_assn)"
    assumes "GEN_ALGO succsi (λsuccsi. (succsi,RETURN o succs)  Ak a list_assn A)"
    assumes "GEN_ALGO emptyi (λFi. (Fi,RETURN o empty)  Ak a bool_assn)"
    assumes [sepref_fr_rules]: "(keyi,RETURN o PR_CONST key)  Ak a K"
    assumes [sepref_fr_rules]: "(copyi, RETURN o COPY)  Ak a A"
    shows
      "(uncurry0 (pw_impl keyi copyi tracei Lei a0i Fi succsi emptyi),
        uncurry0 (RETURN (PR_CONST op_F_reachable)))
       unit_assnk a bool_assn"
  proof -
    from assms interpret
      Worklist_Map2_Impl
        E a0 F "(≼)" succs empty "(⊴)" F' A succsi a0i Fi Lei emptyi key keyi copyi
      by (unfold_locales; simp add: GEN_ALGO_def)

    from pw_impl_hnr_F_reachable show ?thesis by simp
  qed

  sepref_decl_impl hnr_op_F_reachable .

end ― ‹Worklist Map 2›

end ― ‹End of Theory›