Theory Unified_PW_Hashing

theory Unified_PW_Hashing
  imports
    Unified_PW
    Refine_Imperative_HOL.IICF_List_Mset
    Worklist_Algorithms_Misc
    Worklist_Algorithms_Tracing
begin

subsection ‹Towards an Implementation of the Unified Passed-Waiting List›

context Worklist1_Defs
begin

definition "add_pw_unified_spec passed wait a  SPEC (λ(passed',wait',brk).
  if  x  set (succs a). F x then brk
  else passed'  passed  {x  set (succs a). ¬ ( y  passed. x  y)}
       passed  passed'
       wait ⊆# wait'
       wait' ⊆# wait + mset ([x  succs a. ¬ ( y  passed. x  y)])
       ( x  set (succs a).  y  passed'. x  y)
       ( x  set (succs a). ¬ ( y  passed. x  y)  ( y ∈# wait'. x  y))
       ¬ brk)
"

definition "add_pw passed wait a 
    nfoldli (succs a) (λ(_, _, brk). ¬brk)
      (λa (passed, wait, brk). RETURN (
        if F a then
          (passed, wait, True)
        else if  x  passed. a  x then
          (passed, wait, False)
        else (insert a passed, add_mset a wait, False)
      ))
      (passed, wait, False)
"

end ― ‹Worklist1 Defs›

context Worklist1
begin

lemma add_pw_unified_spec_ref:
  "add_pw_unified_spec passed wait a  add_pw_spec passed wait a"
  if "reachable a" "a  passed"
  using succs_correct[OF that(1)] that(2)
  unfolding add_pw_unified_spec_def add_pw_spec_def
  apply simp
  apply safe
                      apply (all auto simp: empty_subsumes; fail | succeed)
  using mset_subset_eqD apply force
    using mset_subset_eqD apply force
  subgoal premises prems
    using prems
    by (auto 4 5 simp: filter_mset_eq_empty_iff intro: trans elim!: subset_mset.ord_le_eq_trans)
      (* s/h *)
  by (clarsimp, smt UnE mem_Collect_eq subsetCE)

lemma add_pw_ref:
  "add_pw passed wait a   Id (add_pw_unified_spec passed wait a)"
  unfolding add_pw_def add_pw_unified_spec_def
  apply (refine_vcg
      nfoldli_rule[where I =
        "λ l1 l2 (passed', wait', brk).
        if brk then  a'  set (succs a). F a'
        else passed'  passed  {x  set l1. ¬ ( y  passed. x  y)}
            passed   passed'
            wait ⊆# wait'
            wait' ⊆# wait + mset [x  l1. ¬ ( y  passed. x  y)]
            ( x  set l1.  y  passed'. x  y)
            ( x  set l1. ¬ ( y  passed. x  y)  ( y ∈# wait'. x  y))
            set l1  Collect F = {}
      "
        ])
     apply (solves auto)
    apply (clarsimp split: if_split_asm)
     apply safe[]
           apply (solves auto simp add: subset_mset.le_iff_add)+
  subgoal premises prems
    using prems trans by (metis (no_types, lifting) Un_iff in_mono mem_Collect_eq)
  by (auto simp: subset_mset.le_iff_add)

end ― ‹Worklist 1›

context Worklist2_Defs
begin

definition "add_pw' passed wait a 
    nfoldli (succs a) (λ(_, _, brk). ¬brk)
      (λa (passed, wait, brk). RETURN (
        if F a then
          (passed, wait, True)
        else if empty a then
          (passed, wait, False)
        else if  x  passed. a  x then
          (passed, wait, False)
        else (insert a passed, add_mset a wait, False)
      ))
      (passed, wait, False)
"

definition pw_algo_unified where
    "pw_algo_unified = do
      {
        if F a0 then RETURN (True, {})
        else if empty a0 then RETURN (False, {})
        else do {
          (passed, wait)  RETURN ({a0}, {#a0#});
          (passed, wait, brk)  WHILEIT pw_inv (λ (passed, wait, brk). ¬ brk  wait  {#})
            (λ (passed, wait, brk). do
              {
                (a, wait)  take_from_mset wait;
                ASSERT (reachable a);
                if empty a then RETURN (passed, wait, brk) else add_pw' passed wait a
              }
            )
            (passed, wait, False);
            RETURN (brk, passed)
        }
      }
    "

end ― ‹Worklist 2 Defs›

context Worklist2
begin

lemma empty_subsumes'2:
  "empty x  x  y  x  y"
  using empty_subsumes' empty_subsumes by auto

lemma bex_or:
  "P  ( x  S. Q x)  ( x  S. P  Q x)" if "S  {}"
  using that by auto

lemma add_pw'_ref':
  "add_pw' passed wait a   (Id  {((p, w, _), _). p  {}  set_mset w  p}) (add_pw passed wait a)"
  if "passed  {}" "set_mset wait  passed"
  unfolding add_pw'_def add_pw_def
  apply (rule nfoldli_refine)
     apply refine_dref_type
  using that apply (solves auto)+
  apply refine_rcg
  apply (rule Set.IntI)
  unfolding z3_rule(44)
   apply (subst bex_or)
  by (auto simp add: empty_subsumes'2)

lemma add_pw'_ref1[refine]:
  "add_pw' passed wait a
    (Id  {((p, w, _), _). p  {}  set_mset w  p}) (add_pw_spec passed' wait' a')"
  if "passed  {}" "set_mset wait  passed" "reachable a" "a  passed"
     and [simp]: "passed = passed'" "wait = wait'" "a = a'"
proof -
  from add_pw_unified_spec_ref[OF that(3-4), of wait] add_pw_ref[of passed wait a] have
    "add_pw passed wait a   Id (add_pw_spec passed wait a)"
    by simp
  moreover note add_pw'_ref'[OF that(1,2), of a]
  ultimately show ?thesis
    by (auto simp: pw_le_iff refine_pw_simps)
qed

lemma refine_weaken:
  "p   R p'" if "p   S p'" "S  R"
  using that by (simp add: pw_le_iff refine_pw_simps; blast)

lemma add_pw'_ref:
  "add_pw' passed wait a 
     ({((p, w, b), (p', w', b')). p  {}  p = p'  set_mset w  w = w'  b = b'})
      (add_pw_spec passed' wait' a')"
  if "passed  {}" "set_mset wait  passed" "reachable a" "a  passed"
     and [simp]: "passed = passed'" "wait = wait'" "a = a'"
  by (rule add_pw'_ref1[OF that, THEN refine_weaken]; auto)

lemma
  "(({a0}, {#a0#}, False), {}, {#a0#}, False)
   {((p, w, b), (p', w', b')). p = p'  set_mset w'  w = w'  b = b'}"
  by auto

lemma [refine]:
  "RETURN ({a0}, {#a0#})   (Id  {((p, w), (p', w')). p  {}  set_mset w  p}) init_pw_spec"
  if "¬ empty a0"
  using that unfolding init_pw_spec_def by (auto simp: pw_le_iff refine_pw_simps)

lemma [refine]:
  "take_from_mset wait 
     {((x, wait), (y, wait')). x = y  wait = wait'  set_mset wait  passed  x  passed}
      (take_from_mset wait')"
  if "wait = wait'" "set_mset wait  passed" "wait  {#}"
  using that
  by (auto 4 5 simp: pw_le_iff refine_pw_simps dest: in_diffD dest!: take_from_mset_correct)

lemma pw_algo_unified_ref:
  "pw_algo_unified   Id pw_algo"
  unfolding pw_algo_unified_def pw_algo_def
  by refine_rcg (auto simp: init_pw_spec_def)

end ― ‹Worklist 2›

subsubsection ‹Utilities›

definition take_from_list where
  "take_from_list s = ASSERT (s  [])  SPEC (λ (x, s'). s = x # s')"

lemma take_from_list_correct:
  assumes "s  []"
  shows "take_from_list s  SPEC (λ (x, s'). s = x # s')"
using assms unfolding take_from_list_def by simp

lemmas [refine_vcg] = take_from_list_correct[THEN order.trans]

context Worklist_Map_Defs
begin

definition
  "add_pw'_map passed wait a 
   nfoldli (succs a) (λ(_, _, brk). ¬brk)
    (λa (passed, wait, _).
      do {
      RETURN (
        if F a then (passed, wait, True) else
        let k = key a; passed' = (case passed k of Some passed'  passed' | None  {})
        in
          if empty a then
            (passed, wait, False)
          else if  x  passed'. a  x then
            (passed, wait, False)
          else
            (passed(k  (insert a passed')), a # wait, False)
        )
      }
    )
    (passed,wait,False)"

definition
  "pw_map_inv  λ (passed, wait, brk).
     passed' wait'.
      (passed, passed')  map_set_rel  (wait, wait')  list_mset_rel 
      pw_inv (passed', wait', brk)
  "

definition pw_algo_map where
  "pw_algo_map = do
    {
      if F a0 then RETURN (True, Map.empty)
      else if empty a0 then RETURN (False, Map.empty)
      else do {
        (passed, wait)  RETURN ([key a0  {a0}], [a0]);
        (passed, wait, brk)  WHILEIT pw_map_inv (λ (passed, wait, brk). ¬ brk  wait  [])
          (λ (passed, wait, brk). do
            {
              (a, wait)  take_from_list wait;
              ASSERT (reachable a);
              if empty a then RETURN (passed, wait, brk) else add_pw'_map passed wait a
            }
          )
          (passed, wait, False);
          RETURN (brk, passed)
      }
    }
  "

end ― ‹Worklist Map Defs›

lemma ran_upd_cases:
  "(x  ran m)  (x = y)" if "x  ran (m(a  y))"
  using that unfolding ran_def by (auto split: if_split_asm)

lemma ran_upd_cases2:
  "( k. m k = Some x  k  a)  (x = y)" if "x  ran (m(a  y))"
  using that unfolding ran_def by (auto split: if_split_asm)

context Worklist_Map
begin

lemma add_pw'_map_ref[refine]:
  "add_pw'_map passed wait a   (map_set_rel ×r list_mset_rel ×r bool_rel) (add_pw' passed' wait' a')"
  if "(passed, passed')  map_set_rel" "(wait, wait')  list_mset_rel" "(a, a')  Id"
  using that
  unfolding add_pw'_map_def add_pw'_def
  apply refine_rcg
     apply refine_dref_type
     apply (solves auto)
    apply (solves auto)
   apply (solves auto)
  subgoal premises assms for a a' _ _ passed' _ wait' f' passed _ wait f
  proof -
    from assms have [simp]: "a' = a" "f = f'" by simp+
    from assms have rel_passed: "(passed, passed')  map_set_rel" by simp
    then have union: "passed' = (ran passed)"
      unfolding map_set_rel_def by auto
    from assms have rel_wait: "(wait, wait')  list_mset_rel" by simp
    from rel_passed have keys[simp]: "key v = k" if "passed k = Some xs" "v  xs" for k xs v
      using that unfolding map_set_rel_def by auto
    define k where "k  key a"
    define xs where "xs  case passed k of None  {} | Some p  p"
    have xs_ran: "x  (ran passed)" if "x  xs" for x
      using that unfolding xs_def ran_def by (auto split: option.split_asm)
    have *: "(x  xs. a  x)  (xpassed'. a'  x)"
    proof standard
      assume "xxs. a  x"
      with rel_passed show "xpassed'. a'  x"
        unfolding xs_def union by (auto intro: ranI split: option.split_asm)
    next
      assume "xpassed'. a'  x"
      with rel_passed show "xxs. a  x" unfolding xs_def union ran_def k_def map_set_rel_def
        using empty_subsumes'2 by force
    qed
    have "(passed(k  insert a xs), insert a' passed')  map_set_rel"
      using (passed, passed')  map_set_rel
      unfolding map_set_rel_def
      apply safe
      subgoal
        unfolding union by (auto dest!: ran_upd_cases xs_ran)
      subgoal
        unfolding ran_def by auto
      subgoal for a''
        unfolding union ran_def
        apply clarsimp
        subgoal for k'
          unfolding xs_def by (cases "k' = k") auto
        done
      by (clarsimp split: if_split_asm, safe,
          auto intro!: keys simp: xs_def k_def split: option.split_asm if_split_asm)
    with rel_wait rel_passed show ?thesis
      unfolding *[symmetric]
      unfolding xs_def k_def Let_def
      unfolding list_mset_rel_def br_def
      by auto
  qed
done

lemma init_map_ref[refine]:
  "(([key a0  {a0}], [a0]), {a0}, {#a0#})  map_set_rel ×r list_mset_rel"
  unfolding map_set_rel_def list_mset_rel_def br_def by auto

lemma take_from_list_ref[refine]:
  "take_from_list xs   (Id ×r list_mset_rel) (take_from_mset ms)" if "(xs, ms)  list_mset_rel"
  using that unfolding take_from_list_def take_from_mset_def list_mset_rel_def br_def
  by (clarsimp simp: pw_le_iff refine_pw_simps)

lemma pw_algo_map_ref:
  "pw_algo_map   (Id ×r map_set_rel) pw_algo_unified"
  unfolding pw_algo_map_def pw_algo_unified_def
  apply refine_rcg
  unfolding pw_map_inv_def list_mset_rel_def br_def map_set_rel_def by auto


end ― ‹Worklist Map›

context Worklist_Map2_Defs
begin

definition
  "add_pw'_map2 passed wait 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; passed' = (case passed k of Some passed'  passed' | None  {})
          in
            if  x  passed'. a  x then
              (passed, wait, False)
            else
              (passed(k  (insert a passed')), a # wait, False)
        )
      }
    )
    (passed,wait,False)"

definition pw_algo_map2 where
  "pw_algo_map2 = do
    {
      if F a0 then RETURN (True, Map.empty)
      else if empty a0 then RETURN (False, Map.empty)
      else do {
        (passed, wait)  RETURN ([key a0  {a0}], [a0]);
        (passed, wait, brk)  WHILEIT pw_map_inv (λ (passed, wait, brk). ¬ brk  wait  [])
          (λ (passed, wait, brk). do
            {
              (a, wait)  take_from_list wait;
              ASSERT (reachable a);
              if empty a
              then RETURN (passed, wait, brk)
              else do {
                TRACE (ExploredState); add_pw'_map2 passed wait a
              }
            }
          )
          (passed, wait, False);
          RETURN (brk, passed)
      }
    }
  "

end ― ‹Worklist Map 2 Defs›

context Worklist_Map2
begin

lemma add_pw'_map2_ref[refine]:
  "add_pw'_map2 passed wait a   Id (add_pw'_map passed' wait' a')"
  if "(passed, passed')  Id" "(wait, wait')  Id" "(a, a')  Id"
  using that
  unfolding add_pw'_map2_def add_pw'_map_def
  apply refine_rcg
     apply refine_dref_type
  by (auto simp: F_split)

lemma pw_algo_map2_ref[refine]:
  "pw_algo_map2   Id pw_algo_map"
  unfolding pw_algo_map2_def pw_algo_map_def TRACE_bind
  apply refine_rcg
           apply refine_dref_type
  by auto

end ― ‹Worklist Map 2›

lemma (in Worklist_Map2_finite) pw_algo_map2_correct:
  "pw_algo_map2  SPEC (λ (brk, passed).
    (brk  F_reachable) 
    (¬ brk 
      ( p.
        (passed, p)  map_set_rel  (a. reachable a  ¬ empty a  (bp. a  b))
         p  {a. reachable a  ¬ empty a})
    )
   )"
proof -
  note pw_algo_map2_ref
  also note pw_algo_map_ref
  also note pw_algo_unified_ref
  also note pw_algo_correct
  finally show ?thesis
    unfolding conc_fun_def Image_def by (fastforce intro: Orderings.order.trans) (* Slow *)
qed

end ― ‹End of Theory›