Theory Worklist_Subsumption1

(* Authors: Lammich, Wimmer *)
theory Worklist_Subsumption1
  imports Worklist_Subsumption_Multiset
begin

subsection ‹From Multisets to Lists›

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 Search_Space_Defs_Empty
begin

  definition "worklist_inv_frontier_list passed wait =
    ( a  passed.  a'. E a a'  ¬ empty a'  ( b'  passed  set wait. a'  b'))"

  definition "start_subsumed_list passed wait = ( a  passed  set wait. a0  a)"

  definition "worklist_inv_list  λ (passed, wait, brk).
    passed  Collect reachable 
    (brk  ( f. reachable f  F f)) 
    (¬ brk 
      worklist_inv_frontier_list passed wait
     ( a  passed  set wait. ¬ F a)
     start_subsumed_list passed wait
     set wait  Collect reachable)
     ( a  passed. ¬ empty a)  ( a  set wait. ¬ empty a)
    "

  definition "add_succ_spec_list wait a  SPEC (λ(wait',brk).
    (
    if a'. E a a'  F a' then
      brk
    else
      ¬brk  set wait'  set wait  {a' . E a a'} 
      ( s  set wait  {a' . E a a'  ¬ empty a'}.  s'  set wait'. s  s')
    )  ( s  set wait'. ¬ empty s)
  )"

end ― ‹Search Space Empty Defs›

context Search_Space''_Defs
begin
  definition worklist_algo_list where
    "worklist_algo_list = do
      {
        if F a0 then RETURN True
        else do {
          let passed = {};
          let wait = [a0];
          (passed, wait, brk)  WHILEIT worklist_inv_list (λ (passed, wait, brk). ¬ brk  wait  [])
            (λ (passed, wait, brk). do
              {
                (a, wait)  take_from_list wait;
                ASSERT (reachable a);
                if ( a'  passed. a  a') then RETURN (passed, wait, brk) else
                do
                  {
                    (wait,brk)  add_succ_spec_list wait a;
                    let passed = insert a passed;
                    RETURN (passed, wait, brk)
                  }
              }
            )
            (passed, wait, False);
            RETURN brk
        }
      }
    "

end ― ‹Search Space'' Defs›

context Search_Space''_pre
begin

  lemma worklist_algo_list_inv_ref:
    fixes x x'
    assumes
      "¬ F a0" "¬ F a0"
      "(x, x')  {((passed,wait,brk), (passed',wait',brk')). passed = passed'  mset wait = wait'  brk = brk' }"
      "worklist_inv' x'"
    shows "worklist_inv_list x"
    using assms
    unfolding worklist_inv'_def worklist_inv_def worklist_inv_list_def
    unfolding worklist_inv_frontier_def worklist_inv_frontier_list_def
    unfolding worklist_start_subsumed_def start_subsumed_list_def
    by auto

  lemma take_from_list_take_from_mset_ref[refine]:
    "take_from_list xs   {((x, xs),(y, m)). x = y  mset xs = m} (take_from_mset m)"
    if "mset xs = m"
    using that unfolding take_from_list_def take_from_mset_def
    by (clarsimp simp: pw_le_iff refine_pw_simps)

  lemma add_succ_spec_list_add_succ_spec_ref[refine]:
    "add_succ_spec_list xs b   {((xs, b), (m, b')). mset xs = m  b = b'} (add_succ_spec' m b')"
    if "mset xs = m" "b = b'"
    using that unfolding add_succ_spec_list_def add_succ_spec'_def
    by (clarsimp simp: pw_le_iff refine_pw_simps)

  lemma worklist_algo_list_ref[refine]: "worklist_algo_list  Id worklist_algo'"
    unfolding worklist_algo_list_def worklist_algo'_def
    apply (refine_rcg)
               apply blast
              prefer 2
              apply (rule worklist_algo_list_inv_ref; assumption)
    by auto

end ― ‹Search Space''›


subsection ‹Towards an Implementation›
context Worklist1_Defs
begin

  definition
    "add_succ1 wait a 
     nfoldli (succs a) (λ(_,brk). ¬brk)
      (λa (wait,brk).
        do {
        ASSERT ( x  set wait. ¬ empty x);
        if F a then RETURN (wait,True) else RETURN (
          if ( x  set wait. a  x  ¬ x  a)  empty a
          then [x  wait. ¬ x  a]
          else a # [x  wait. ¬ x  a],False)
        }
      )
      (wait,False)"

end

context Worklist2_Defs
begin

  definition
    "add_succ1' wait a 
     nfoldli (succs a) (λ(_,brk). ¬brk)
      (λa (wait,brk).
        if F a then RETURN (wait,True) else RETURN (
          if empty a
          then wait
          else if  x  set wait. a  x  ¬ x  a
          then [x  wait. ¬ x  a]
          else a # [x  wait. ¬ x  a],False)
      )
      (wait,False)"

end

context Worklist1
begin

lemma add_succ1_ref[refine]:
  "add_succ1 wait a  (Id ×r bool_rel) (add_succ_spec_list wait' a')"
  if "(wait,wait')Id" "(a,a')b_rel Id reachable" " x  set wait'. ¬ empty x"
  using that
  apply simp
  unfolding add_succ_spec_list_def add_succ1_def
  apply (refine_vcg nfoldli_rule[where I =
        "λl1 _ (wait',brk).
            (if brk then a'. E a a'  F a'
            else set wait'  set wait  set l1  set l1  Collect F = {}
               ( x  set wait  set l1. ¬ empty x  ( x'  set wait'. x  x')))
             ( x  set wait'. ¬ empty x)"]
        )
            apply (solves auto)
           apply (solves auto)
          using succs_correct[of a] apply (solves auto)
         using succs_correct[of a] apply (solves auto)
        apply (solves auto)
  subgoal
    apply (clarsimp split: if_split_asm; intro conjI)
        apply blast
       apply blast
      apply (meson empty_mono local.trans)
     apply blast
    apply (meson empty_mono local.trans)
    done
   using succs_correct[of a] apply (solves auto)+
  done

end

context Worklist2
begin

  lemma add_succ1'_ref[refine]:
    "add_succ1' wait a  (Id ×r bool_rel) (add_succ1 wait' a')"
    if "(wait,wait')Id" "(a,a')b_rel Id reachable" " x  set wait'. ¬ empty x"
    unfolding add_succ1'_def add_succ1_def
    using that
    apply (refine_vcg nfoldli_refine)
         apply refine_dref_type
         apply (solves auto simp: empty_subsumes' cong: filter_cong)+
    apply (simp add: empty_subsumes' cong: filter_cong)
    by (metis empty_mono empty_subsumes' filter_True)


  lemma add_succ1'_ref'[refine]:
    "add_succ1' wait a  (Id ×r bool_rel) (add_succ_spec_list wait' a')"
    if "(wait,wait')Id" "(a,a')b_rel Id reachable" " x  set wait'. ¬ empty x"
    using that
  proof -
    note add_succ1'_ref
    also note add_succ1_ref
    finally show ?thesis
      using that by - auto
  qed

  definition worklist_algo1' where
    "worklist_algo1' = do
      {
        if F a0 then RETURN True
        else do {
          let passed = {};
          let wait = [a0];
          (passed, wait, brk)  WHILEIT worklist_inv_list (λ (passed, wait, brk). ¬ brk  wait  [])
            (λ (passed, wait, brk). do
              {
                (a, wait)  take_from_list wait;
                if ( a'  passed. a  a') then RETURN (passed, wait, brk) else
                do
                  {
                    (wait,brk)  add_succ1' wait a;
                    let passed = insert a passed;
                    RETURN (passed, wait, brk)
                  }
              }
            )
            (passed, wait, False);
            RETURN brk
        }
      }
    "

  lemma take_from_list_ref[refine]:
    "take_from_list wait 
      {((x, wait), (y, wait')). x = y  wait = wait'  ¬ empty x  ( a  set wait. ¬ empty a)}
       (take_from_list wait')"
    if "wait = wait'" " a  set wait. ¬ empty a" "wait  []"
    using that
    by (auto 4 4 simp: pw_le_iff refine_pw_simps dest!: take_from_list_correct)

  lemma worklist_algo1_list_ref[refine]: "worklist_algo1'  Id worklist_algo_list"
    unfolding worklist_algo1'_def worklist_algo_list_def
    apply (refine_rcg)
    apply refine_dref_type
    unfolding worklist_inv_list_def
    by auto

  definition worklist_algo1 where
    "worklist_algo1  if empty a0 then RETURN False else worklist_algo1'"

  lemma worklist_algo1_ref[refine]: "worklist_algo1  Id worklist_algo''"
  proof -
    have "worklist_algo1'  worklist_algo'" if "¬ empty a0"
    proof -
      note worklist_algo1_list_ref
      also note worklist_algo_list_ref
      finally show "worklist_algo1'  worklist_algo'"
        by simp
    qed
    then show ?thesis
      unfolding worklist_algo1_def worklist_algo''_def by simp
  qed

end ― ‹Worklist2›

context Worklist3_Defs
begin

  definition
    "add_succ2 wait a 
     nfoldli (succs a) (λ(_,brk). ¬brk)
      (λa (wait,brk).
        if empty a then RETURN (wait, False)
        else if F' a then RETURN (wait,True)
        else RETURN (
          if  x  set wait. a  x  ¬ x  a
          then [x  wait. ¬ x  a]
          else a # [x  wait. ¬ x  a],False)
      )
      (wait,False)"

  definition
    "filter_insert_wait wait a 
     if  x  set wait. a  x  ¬ x  a
     then [x  wait. ¬ x  a]
     else a # [x  wait. ¬ x  a]"

end


context Worklist3
begin

  lemma filter_insert_wait_alt_def:
    "filter_insert_wait wait a = (
      let
         (f, xs) =
           fold (λ x (f, xs). if x  a then (f, xs) else (f  a  x, x # xs)) wait (False, [])
       in
         if f then rev xs else a # rev xs
    )
    "
  proof -
    have
      "fold (λ x (f, xs). if x  a then (f, xs) else (f  a  x, x # xs)) wait (f, xs)
     = (f  ( x  set wait. a  x  ¬ x  a), rev [x  wait. ¬ x  a] @ xs)" for f xs
      by (induction wait arbitrary: f xs; simp)
    then show ?thesis unfolding filter_insert_wait_def by auto
  qed

  lemma add_succ2_alt_def:
    "add_succ2 wait a 
     nfoldli (succs a) (λ(_,brk). ¬brk)
      (λa (wait,brk).
        if empty a then RETURN (wait, False)
        else if F' a then RETURN (wait, True)
        else RETURN (filter_insert_wait wait a, False)
      )
      (wait,False)"
    unfolding add_succ2_def filter_insert_wait_def by (intro HOL.eq_reflection HOL.refl)

  lemma add_succ2_ref[refine]:
    "add_succ2 wait a  (Id ×r bool_rel) (add_succ1' wait' a')"
    if "(wait,wait')Id" "(a,a')Id"
    unfolding add_succ2_def add_succ1'_def
    apply (rule nfoldli_refine)
       apply refine_dref_type
    using that by (auto simp: F_split)

  definition worklist_algo2' where
    "worklist_algo2' = do
      {
        if F' a0 then RETURN True
        else do {
          let passed = {};
          let wait = [a0];
          (passed, wait, brk)  WHILEIT worklist_inv_list (λ (passed, wait, brk). ¬ brk  wait  [])
            (λ (passed, wait, brk). do
              {
                (a, wait)  take_from_list wait;
                if ( a'  passed. a  a') then RETURN (passed, wait, brk) else
                do
                  {
                    (wait,brk)  add_succ2 wait a;
                    let passed = insert a passed;
                    RETURN (passed, wait, brk)
                  }
              }
            )
            (passed, wait, False);
            RETURN brk
        }
      }
    "

  lemma worklist_algo2'_ref[refine]: "worklist_algo2'  Id worklist_algo1'" if "¬ empty a0"
    unfolding worklist_algo2'_def worklist_algo1'_def
    using that
    supply take_from_list_ref [refine del]
    apply refine_rcg
              apply refine_dref_type
    by (auto simp: F_split)

  definition worklist_algo2 where
    "worklist_algo2  if empty a0 then RETURN False else worklist_algo2'"

  lemma worklist_algo2_ref[refine]: "worklist_algo2  Id worklist_algo''"
  proof -
    have "worklist_algo2  Id worklist_algo1"
      unfolding worklist_algo2_def worklist_algo1_def
      by refine_rcg standard
    also note worklist_algo1_ref
    finally show ?thesis .
  qed
end ― ‹Worklist3›

end ― ‹Theory›