Theory Weak_Set

theory Weak_Set
imports
  Autoref_Misc
begin

subsection ‹generic things›

lemma nres_rel_trans1: "a  b  (b, i)  Rnres_rel  (a, i)  Rnres_rel"
  using nres_relD order_trans
  by (blast intro: nres_relI)

lemma nres_rel_trans2: "a  b  (i, a)  Rnres_rel  (i, b)  Rnres_rel"
  using nres_relD
  by (blast intro: nres_relI ref_two_step)

lemma param_Union[param]: "(Union, Union)  Rset_relset_rel  Rset_rel"
  by (fastforce simp: set_rel_def)

subsection ‹relation›

definition list_wset_rel_internal_def: "list_wset_rel R = br set top O Rset_rel"

lemma list_wset_rel_def: "Rlist_wset_rel = br set top O Rset_rel"
  unfolding list_wset_rel_internal_def[abs_def] by (simp add: relAPP_def)

lemma list_wset_rel_br_eq: "br a Ilist_wset_rel = br (λxs. a ` set xs) (λxs. x  set xs. I x)"
  by (auto simp: list_wset_rel_def br_def set_rel_def)

lemma mem_br_list_wset_rel_iff:
  "(xs, X)  br a Ilist_wset_rel  (X = (a ` set xs)  (x  set xs. I x))"
  by (auto simp: list_wset_rel_def set_rel_def br_def)

lemma list_set_rel_sv[relator_props]:
  "single_valued R  single_valued (Rlist_wset_rel)"
  unfolding list_wset_rel_def
  by tagged_solver

lemmas [autoref_rel_intf] = REL_INTFI[of list_wset_rel i_set]

lemma list_wset_relD:
  assumes "(a, b)  Rlist_wset_rel"
  shows "(set a, b)  Rset_rel"
  using assms
  by (auto simp: list_wset_rel_def br_def)


subsection ‹operations›

definition "op_set_ndelete x X = RES {X - {x}, X}"

lemma op_set_ndelete_spec: "op_set_ndelete x X = SPEC(λR. R = X - {x}  R = X)"
  by (auto simp: op_set_ndelete_def)


subsection ‹implementations›

lemma list_wset_autoref_empty[autoref_rules]:
  "([],{})Rlist_wset_rel"
  by (auto simp: list_wset_rel_def br_def relcompI)

context includes autoref_syntax begin

lemma mem_set_list_relE1:
  assumes "(xs, ys)  Rlist_rel"
  assumes "x  set xs"
  obtains y where "y  set ys" "(x, y)  R"
  by (metis (no_types, lifting) assms in_set_conv_decomp list_relE3 list_rel_append1)

lemma mem_set_list_relE2:
  assumes "(xs, ys)  Rlist_rel"
  assumes "y  set ys"
  obtains x where "x  set xs" "(x, y)  R"
  by (metis assms in_set_conv_decomp list_relE4 list_rel_append2)

lemma in_domain_list_relE:
  assumes "x. x  set xs  x  Domain R"
  obtains ys where "(xs, ys)  Rlist_rel"
proof -
  obtain y where y: "x. x  set xs  (x, y x)  R"
    using assms by (metis for_in_RI)
  have "(xs, map y xs)  Rlist_rel"
    by (auto simp: list_rel_def list_all2_iff in_set_zip intro!: y)
  then show ?thesis ..
qed

lemma list_rel_comp_list_wset_rel:
  assumes "single_valued R"
  shows "Rlist_rel O Slist_wset_rel = R O Slist_wset_rel"
proof (safe, goal_cases)
  case hyps: (1 a b x y z)
  show ?case
    unfolding list_wset_rel_def
  proof (rule relcompI[where b = "set x"])
    show "(set x, z)  R O Sset_rel"
      unfolding set_rel_def
      using hyps 
      by (clarsimp simp: list_wset_rel_def br_def set_rel_def)
        (meson mem_set_list_relE1 mem_set_list_relE2 relcomp.relcompI)
  qed (simp add: br_def)
next
  case hyps: (2 xs zs)
  then have "x. x  set xs  x  Domain R"
    by (auto simp: list_wset_rel_def br_def set_rel_def)
  from in_domain_list_relE[OF this]
  obtain ys where ys: "(xs, ys)  Rlist_rel" .
  have set_rel: "(set ys, zs)  Sset_rel"
    unfolding list_wset_rel_def set_rel_def
    using hyps
    by (clarsimp simp: list_wset_rel_def br_def set_rel_def)
      (metis (full_types) assms mem_set_list_relE1 mem_set_list_relE2 relcompEpair single_valued_def ys)
  from ys show ?case
    by (rule relcompI)
      (auto simp: list_wset_rel_def br_def intro!: relcompI[where b="set ys"] set_rel)
qed

lemma list_set_autoref_insert[autoref_rules]:
  assumes "PREFER single_valued R"
  shows "(Cons,Set.insert)  R  Rlist_wset_rel  Rlist_wset_rel"
proof -
  have 1: "(Cons, Cons)  R  Rlist_rel  Rlist_rel"
    by parametricity
  moreover have 2: "(Cons, Set.insert)  Id  Idlist_wset_rel  Idlist_wset_rel"
    by (auto simp: list_wset_rel_def br_def)
  ultimately have "(Cons, Set.insert)  (R  Rlist_rel  Rlist_rel) O (Id  Idlist_wset_rel  Idlist_wset_rel)"
    by auto
  also have "  R  Rlist_wset_rel  Rlist_wset_rel"
  proof -
    have "Rlist_rel O Idlist_wset_rel  Rlist_rel O Idlist_wset_rel 
        Rlist_wset_rel  Rlist_wset_rel"
      by (rule fun_rel_mono)
        (simp_all add: list_rel_comp_list_wset_rel assms[unfolded autoref_tag_defs])
    then have "(Rlist_rel  Rlist_rel) O (Idlist_wset_rel  Idlist_wset_rel) 
        Rlist_wset_rel  Rlist_wset_rel"
      by (rule order_trans[OF fun_rel_comp_dist])
    from _ this have
      "R O Id  (Rlist_rel  Rlist_rel) O (Idlist_wset_rel  Idlist_wset_rel) 
        R  Rlist_wset_rel  Rlist_wset_rel"
      by (rule fun_rel_mono) simp
    then show ?thesis
      by (rule order_trans[OF fun_rel_comp_dist])
  qed
  finally show ?thesis .
qed

lemma op_set_ndelete_wset_refine[autoref_rules]:
  assumes "PREFER single_valued R"
  assumes "(x, y)  R" "(xs, Y)  Rlist_wset_rel"
  shows "(nres_of (dRETURN (List.remove1 x xs)),op_set_ndelete $ y $ Y)  Rlist_wset_relnres_rel"
proof -
  from assms(3)[unfolded list_wset_rel_def]
  obtain u where u: "(xs, u)  br set top" "(u, Y)  Rset_rel"
    by (rule relcompE) auto
  have "x'. (remove1 x xs, x')  Rlist_wset_rel  (x' = Y - {y}  x' = Y)"
  proof (cases "x  set (remove1 x xs)")
    case True
    then have "set (remove1 x xs) = set xs"
      by (metis in_set_remove1 set_remove1_subset subsetI subset_antisym)
    then show ?thesis
      using True u
      by (auto intro!: simp: list_wset_rel_def br_def)
  next
    case False
    then have r: "set (remove1 x xs) = set xs - {x}"
      using in_set_remove1[of _ x xs] u
      by (auto simp del: in_set_remove1 simp add: br_def)
    from assms old_set_rel_sv_eq[of R] have [simp]: "Rset_rel = Rold_set_rel" by simp
    show ?thesis
      using False (x, y)  R assms
      by (auto simp: relcomp_unfold r old_set_rel_def single_valued_def br_def list_wset_rel_def)
  qed
  then show ?thesis
    unfolding op_set_ndelete_spec autoref_tag_defs
    by (safe intro!: nres_relI SPEC_refine det_SPEC elim!: relcompE)
qed


subsection ‹pick›

lemma
  pick_wset_refine[autoref_rules]:
  assumes[unfolded autoref_tag_defs, simp]: "SIDE_PRECOND (X  {})"
  assumes "(XS, X)  Alist_wset_rel"
  shows "(nres_of (dRETURN (hd XS)), op_set_pick $ X)  Anres_rel"
proof -
  have "xset XS. yX. (x, y)  A  yX. xset XS. (x, y)  A 
    x'. (hd XS, x')  A  x'  X  xa  X" for xa
    by (metis (full_types) empty_iff insertCI list.exhaust list.sel(1) list.set)
  show ?thesis
    using assms(2)
    unfolding op_set_pick_def[abs_def] autoref_tag_defs
    by (cases XS)
      (auto simp: Let_def list_wset_rel_def set_rel_def br_def intro!: nres_relI RETURN_RES_refine det_SPEC)
qed

subsection ‹pick remove›

definition "op_set_npick_remove X = SPEC (λ(x, X'). x  X  (X' = X - {x}  X' = X))"
lemma op_set_pick_remove_pat[autoref_op_pat]:
  "SPEC (λ(x, X'). x  X  (X' = X - {x}  X' = X))  op_set_npick_remove $ X"
  "SPEC (λ(x, X'). x  X  (X' = X  X' = X - {x}))  op_set_npick_remove $ X"
  "do { x  SPEC (λx. x  X); X'  op_set_ndelete x X; f x X' }  do { (x, X')  op_set_npick_remove X; f x X'}"
  by (auto simp: op_set_npick_remove_def op_set_ndelete_def pw_eq_iff refine_pw_simps intro!: eq_reflection)

lemma op_set_npick_remove_def':
  "X  {}  op_set_npick_remove X =
    do { ASSERT (X  {}); x  op_set_pick X; X'  op_set_ndelete x X; RETURN (x, X')}"
  by (auto simp: op_set_npick_remove_def op_set_ndelete_def pw_eq_iff refine_pw_simps )

lemma aux: "(a, c)  R  a = b  (b, c)  R"
  by simp

lemma
  op_set_npick_remove_refine[autoref_rules]:
  assumes [THEN PREFER_sv_D, relator_props]: "PREFER single_valued A"
  assumes "SIDE_PRECOND (X  {})"
  assumes [autoref_rules]: "(XS, X)  Alist_wset_rel"
  shows "(RETURN (hd XS, tl XS), op_set_npick_remove $ X)  A ×r Alist_wset_relnres_rel"
proof -
  have "(RETURN (hd XS, remove1 (hd XS) XS), ASSERT (X  {})  (λ_. op_set_pick X  (λx. op_set_ndelete x X  (λX'. RETURN (x, X')))))
     A ×r Alist_wset_relnres_rel"
    by (rule aux, autoref, simp)
  then show ?thesis
    unfolding autoref_tag_defs op_set_npick_remove_def'[OF assms(2)[unfolded autoref_tag_defs]]
    using assms
    by (subst remove1_tl[symmetric]) (force simp: list_wset_rel_def br_def set_rel_def)
qed


subsection ‹emptiness check›

lemma isEmpty_wset_refine[autoref_rules]:
  assumes "(xs, X)  Alist_wset_rel"
  shows "(xs = [], op_set_isEmpty $ X)  bool_rel"
  using assms
  by (auto simp: list_wset_rel_def br_def set_rel_def)


subsection ‹union›

lemma union_wset_refine[autoref_rules]:
  "(append, (∪))  Rlist_wset_rel  Rlist_wset_rel  Rlist_wset_rel"
  by (auto 0 3 simp: list_wset_rel_def set_rel_def relcomp_unfold br_def)


subsection ‹of list›

lemma set_wset_refine[autoref_rules]:
  assumes "PREFER single_valued R"
  shows "((λx. x), set)  Rlist_rel  Rlist_wset_rel"
proof (rule fun_relI)
  fix a a'
  assume aa': "(a, a')  Rlist_rel"
  moreover have "(a, a')  Rlist_rel  (set a, set a')  Rset_rel"
    using assms[THEN PREFER_sv_D]
    by parametricity
  ultimately show "(a, set a')  Rlist_wset_rel"
    unfolding list_wset_rel_def
    by (intro relcompI[where b="set a"]) (simp_all add: br_def)
qed


subsection ‹filter set›

lemma bCollect_param: "((λy a. {x  y. a x}), (λz a'. {x  z. a' x}))  Rset_rel  (R  bool_rel)  Rset_rel"
  unfolding set_rel_def
  apply safe
  subgoal using tagged_fun_relD_both by fastforce
  subgoal using tagged_fun_relD_both by fastforce
  done

lemma op_set_filter_list_wset_refine[autoref_rules]:
  "(filter, op_set_filter)  (R  bool_rel)  Rlist_wset_rel  Rlist_wset_rel"
  by (force simp: list_wset_rel_def br_def bCollect_param[param_fo])


subsection ‹bound on cardinality›

definition "op_set_wcard X = SPEC (λc. card X  c)"

lemma op_set_wcard_refine[autoref_rules]: "PREFER single_valued R  ((λxs. RETURN (length xs)), op_set_wcard)  Rlist_wset_rel  Idnres_rel"
proof (auto simp: list_wset_rel_def nres_rel_def br_def op_set_wcard_def, goal_cases)
  case (1 x z)
  thus ?case
    by (induction x arbitrary: z)
      (auto simp: old_set_rel_sv_eq[symmetric] old_set_rel_def Image_insert intro!: card_insert_le_m1)  
qed

lemmas op_set_wcard_spec[refine_vcg] = op_set_wcard_def[THEN eq_refl, THEN order_trans]

subsection ‹big union›

lemma Union_list_wset_rel[autoref_rules]:
  assumes "PREFER single_valued A"
  shows "(concat, Union)  Alist_wset_rellist_wset_rel  Alist_wset_rel"
proof -
  have "(concat, concat)  Alist_rellist_rel  Alist_rel" (is "_  ?A")
    by parametricity
  moreover have "(concat, Union)  Idlist_wset_rellist_wset_rel  Idlist_wset_rel" (is "_  ?B")
    by (auto simp: list_wset_rel_def br_def relcomp_unfold set_rel_def; meson)
  ultimately have "(concat, Union)  ?A O ?B"
    by auto
  also note fun_rel_comp_dist
  finally show ?thesis
    using assms
    by (simp add: list_rel_comp_list_wset_rel list_rel_sv_iff)
qed


subsection ‹image›

lemma image_list_wset_rel[autoref_rules]:
  assumes "PREFER single_valued B"
  shows "(map, (`))  (A  B)  Alist_wset_rel  Blist_wset_rel"
  unfolding list_wset_rel_def relcomp_unfold
proof safe
  fix a a' aa a'a y
  assume H: "(a, a')  A  B" "(aa, y)  br set top" "(y, a'a)  Aset_rel"
  have "(map a aa, a ` y)  br set top"
    using H
    by (auto simp: br_def)
  moreover have " (a ` y, a' ` a'a)  Bset_rel"
    using H
    by (fastforce simp: fun_rel_def set_rel_def split: prod.split)
  ultimately show "y. (map a aa, y)  br set top  (y, a' ` a'a)  Bset_rel"
    by (safe intro!: exI[where x = "a ` y"])
qed

subsection ‹Ball›

lemma Ball_list_wset_rel[autoref_rules]:
  "((λxs p. foldli xs (λx. x) (λa _. p a) True), Ball)  Alist_wset_rel  (A  bool_rel)  bool_rel"
proof -
  have "(set a, a')  Aset_rel  (Ball (set a), Ball a')  (A  bool_rel)  bool_rel" for a a'
    by parametricity
  then have "(λxs. Ball (set xs), Ball)  {(x, z). (set x, z)  Aset_rel}  (A  bool_rel)  bool_rel"
    unfolding mem_Collect_eq split_beta' fst_conv snd_conv
    by (rule fun_relI) auto
  then show ?thesis
    by (simp add: relcomp_unfold br_def foldli_ball_aux list_wset_rel_def)
qed


subsection ‹weak foreach loop›

definition FORWEAK :: "'a set  'b nres  ('a  'b nres)  ('b  'b  'b nres)  'b nres"
where "FORWEAK X d f c =
  (if X = {} then d
  else do {
    (a, X)  op_set_npick_remove X;
    b  f a;
    (b, _)  WHILE (λ(_, X). ¬ op_set_isEmpty X) (λ(b, X).
      do {
        ASSERT (X  {});
        (a, X)  op_set_npick_remove X;
        b'  f a;
        b  c b b';
        RETURN (b, X)
      }) (b, X);
    RETURN b
  })"

schematic_goal
  FORWEAK_wset_WHILE_refine:
  assumes [relator_props]: "single_valued A"
  assumes [autoref_rules]:
    "(Xi, X)  Alist_wset_rel"
    "(di, d)  Bnres_rel"
    "(fi, f)  A  Bnres_rel"
    "(ci, c)  B  B  Bnres_rel"
  shows "(?f, FORWEAK X d f c)  Bnres_rel"
  unfolding FORWEAK_def
  by autoref

lemma FORWEAK_LIST_transfer_nfoldli:
  "nfoldli xs (λ_. True) (λx a. c a x) a  do {
    (a, _) 
      WHILE (λ(a, xs). xs  []) (λ(a, xs). do {
        (x, xs)  RETURN (hd xs, tl xs);
        a  c a x;
        RETURN (a, xs)
      }) (a, xs);
    RETURN a}"
proof (induct xs arbitrary: a)
  case Nil thus ?case by (auto simp: WHILE_unfold)
next
  case (Cons x xs)
  show ?case
    by (auto simp: WHILE_unfold intro!: bind_mono Cons[THEN order.trans])
qed

lemma
  FORWEAK_wset_refine:
  assumes [relator_props]: "PREFER single_valued A"
  assumes [autoref_rules]:
    "(Xi, X)  Alist_wset_rel"
    "(di, d)  Bnres_rel"
    "(fi, f)  A  Bnres_rel"
    "(ci, c)  B  B  Bnres_rel"
  shows
    "((if Xi = [] then di else do { b  fi (hd Xi); nfoldli (tl Xi) (λ_. True) (λx b. do {b'  fi x; ci b b'}) b }),
      (OP FORWEAK ::: Alist_wset_rel  Bnres_rel  (A  Bnres_rel)  (B  B  Bnres_rel)  Bnres_rel) $ X $ d $ f $ c)  Bnres_rel"
  unfolding autoref_tag_defs
  by (rule nres_rel_trans1[OF _ FORWEAK_wset_WHILE_refine[OF assms[simplified autoref_tag_defs]]])
    (auto intro!: bind_mono FORWEAK_LIST_transfer_nfoldli[THEN order.trans])
concrete_definition FORWEAK_LIST for Xi di fi ci uses FORWEAK_wset_refine
lemmas [autoref_rules] = FORWEAK_LIST.refine

schematic_goal FORWEAK_LIST_transfer_nres:
  assumes [refine_transfer]: "nres_of d  d'"
  assumes [refine_transfer]: "x. nres_of (f x)  f' x"
  assumes [refine_transfer]: "x y. nres_of (g x y)  g' x y"
  shows
  "nres_of (?f)  FORWEAK_LIST xs d' f' g'"
  unfolding FORWEAK_LIST_def
  by refine_transfer
concrete_definition dFORWEAK_LIST for xs d f g uses FORWEAK_LIST_transfer_nres
lemmas [refine_transfer] = dFORWEAK_LIST.refine

schematic_goal FORWEAK_LIST_transfer_plain:
  assumes [refine_transfer]: "RETURN d  d'"
  assumes [refine_transfer]: "x. RETURN (f x)  f' x"
  assumes [refine_transfer]: "x y. RETURN (g x y)  g' x y"
  shows "RETURN ?f  FORWEAK_LIST xs d' f' g'"
  unfolding FORWEAK_LIST_def
  by refine_transfer
concrete_definition FORWEAK_LIST_plain for xs f g uses FORWEAK_LIST_transfer_plain
lemmas [refine_transfer] = FORWEAK_LIST_plain.refine

schematic_goal FORWEAK_LIST_transfer_ne_plain:
  assumes "SIDE_PRECOND_OPT (xs  [])"
  assumes [refine_transfer]: "x. RETURN (f x)  f' x"
  assumes [refine_transfer]: "x y. RETURN (g x y)  g' x y"
  shows "RETURN ?f  FORWEAK_LIST xs d' f' g'"
  using assms
  by (simp add: FORWEAK_LIST_def) refine_transfer
concrete_definition FORWEAK_LIST_ne_plain for xs f g uses FORWEAK_LIST_transfer_ne_plain


lemma FORWEAK_empty[simp]: "FORWEAK {} = (λd _ _. d)"
  by (auto simp: FORWEAK_def[abs_def])

lemma FORWEAK_WHILE_casesI:
  assumes "X = {}  d  SPEC P"
  assumes "a X'. a  X  X' = X - {a} 
    f a  SPEC (λx. WHILE (λ(_, X). X  {})
          (λ(b, X).
            do {
              ASSERT (X  {});
              (a, X)  op_set_npick_remove X;
              b'  f a;
              b  c b b';
              RETURN (b, X)
            })
          (x, X')
          SPEC (λ(b, _). RETURN b  SPEC P))"
  assumes "a. a  X 
    f a  SPEC (λx. WHILE (λ(_, X). X  {})
          (λ(b, X).
            do {
              ASSERT (X  {});
              (a, X)  op_set_npick_remove X;
              b'  f a;
              b  c b b';
              RETURN (b, X)
            })
          (x, X)
          SPEC (λ(b, _). RETURN b  SPEC P))"
  shows "FORWEAK X d f c  SPEC P"
  unfolding FORWEAK_def
  apply (cases "X = {}")
  subgoal by (simp add: assms(1))
  subgoal
    supply op_set_npick_remove_def[refine_vcg_def]
    apply (refine_vcg)
    apply clarsimp
    apply (erule disjE)
    subgoal
      by (refine_vcg assms(2))
    subgoal
      by (refine_vcg assms(3))
    done
  done

lemma FORWEAK_invarI:
  fixes I::"'b  'a set  bool"
  assumes "X = {}  d  SPEC P"
  assumes fspec_init1[THEN order_trans]: "a. a  X  f a  SPEC (λx. I x (X - {a}))"
  assumes fspec_init2[THEN order_trans]: "a. a  X  f a  SPEC (λx. I x X)"
  assumes fspec_invar1[THEN order_trans]:
    "a aa b ba. I aa b  a  b  f a  SPEC (λxb. c aa xb  SPEC (λr. I r (b - {a})))"
  assumes fspec_invar2[THEN order_trans]: "a aa b ba. I aa b  a  b  f a  SPEC (λxb. c aa xb  SPEC (λr. I r b))"
  assumes fin: "aa. I aa {}  P aa"
  shows "FORWEAK X d f c  SPEC P"
  unfolding FORWEAK_def
  apply (cases "X = {}")
  subgoal by (simp add: assms(1))
  subgoal
    supply op_set_npick_remove_def[refine_vcg_def]
    apply (refine_vcg)
    apply clarsimp
    apply (erule disjE)
    subgoal
      apply (refine_vcg fspec_init1)
      apply (rule order_trans[OF WHILE_le_WHILEI[where I="λ(a, b). I a b"]])
      apply (refine_vcg)
      subgoal
        apply clarsimp
        apply (erule disjE)
        subgoal by (rule fspec_invar1, assumption, assumption)  (refine_vcg)
        subgoal by (rule fspec_invar2, assumption, assumption)  (refine_vcg)
        done
      subgoal by (simp add: fin)
      done
    subgoal
      apply (refine_vcg fspec_init2)
      apply (rule order_trans[OF WHILE_le_WHILEI[where I="λ(a, b). I a b"]])
      apply (refine_vcg)
      subgoal
        apply clarsimp
        apply (erule disjE)
        subgoal by (rule fspec_invar1, assumption, assumption)  (refine_vcg)
        subgoal by (rule fspec_invar2, assumption, assumption)  (refine_vcg)
        done
      subgoal by (simp add: fin)
      done
    done
  done

lemma FORWEAK_mono_rule:
  fixes f::"'d  'e nres" and c::"'e  'e  'e nres" and I::"'d set  'e  bool"
  assumes empty: "S = {}  d  SPEC P"
  assumes I0[THEN order_trans]: "s. s  S  f s  SPEC (I {s})"
  assumes I_mono: "it it' σ. I it σ  it'  it  it  S  I it' σ"
  assumes IP[THEN order_trans]:
    "x it σ.  xS; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I (insert x it)))"
  assumes II: "σ. I S σ  P σ"
  shows "FORWEAK S d f c  SPEC P"
  apply (rule FORWEAK_invarI[where I="λb X. X  S  I (S - X) b"])
  subgoal by (rule empty)
  subgoal by (auto simp: Diff_Diff_Int intro!: I0)
  subgoal
    by (metis (mono_tags, lifting) Diff_cancel I0 I_mono Refine_Basic.RES_sng_eq_RETURN iSPEC_rule
        less_eq_nres.simps(2) nres_order_simps(21) subset_insertI subset_refl)
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: order_trans)
    done
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: I_mono)
    done
  subgoal by (auto intro!: II)
  done

lemma FORWEAK_case_rule:
  fixes f::"'d  'e nres" and c::"'e  'e  'e nres" and I::"'d set  'e  bool"
  assumes empty: "S = {}  d  SPEC P"
  assumes I01[THEN order_trans]: "s. s  S  f s  SPEC (I (S - {s}))"
  assumes I02[THEN order_trans]: "s. s  S  f s  SPEC (I S)"
  assumes IP1[THEN order_trans]:
    "x it σ.  xit; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I (it-{x})))"
  assumes IP2[THEN order_trans]:
    "x it σ.  xit; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I it))"
  assumes II: "σ. I {} σ  P σ"
  shows "FORWEAK S d f c  SPEC P"
  apply (rule FORWEAK_invarI[where I = "λa b. I b a  b  S"])
  subgoal by (rule empty)
  subgoal by (rule I01) auto
  subgoal by (rule I02) auto
  subgoal for a b it
    apply (rule IP1[of a it b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      by (rule order_trans, assumption) auto
    done
  subgoal by (rule IP2) auto
  subgoal by (rule II) auto
  done

lemma FORWEAK_elementwise_rule:
  assumes "nofail d"
  assumes Inf_spec: "X. X  XX  Inf_spec X  SPEC (Q X)"
  notes [refine_vcg] = order.trans[OF Inf_spec]
  assumes comb_spec1: "a b X Y. Q X a  comb a b  SPEC (Q X)"
  assumes comb_spec2: "a b X Y. Q X b  comb a b  SPEC (Q X)"
  shows "FORWEAK XX d Inf_spec comb  SPEC (λi. xXX. Q x i)"
  apply (rule FORWEAK_mono_rule[where I="λS i. xS. Q x i"])
  subgoal using nofail d by (simp add: nofail_SPEC_iff)
  subgoal by (simp add: Diff_Diff_Int Inf_spec)
  subgoal by force
    subgoal for x it σ
      apply (refine_transfer refine_vcg)
      apply (rule SPEC_BallI)
      apply (rule SPEC_nofail)
      apply (rule comb_spec2)
      apply assumption
      subgoal for y z
        apply (cases "z = x")
        subgoal by simp (rule comb_spec2)
        subgoal by (rule comb_spec1) force
        done
      done
    subgoal by force
  done

end

lemma nofail_imp_RES_UNIV: "nofail s  s  RES UNIV"
  by (metis Refine_Basic.nofail_SPEC_triv_refine UNIV_I top_empty_eq top_set_def)

lemma FORWEAK_unit_rule[THEN order_trans, refine_vcg]:
  assumes "nofail d"
  assumes "s. nofail (f s)"
  assumes "nofail (c () ())"
  shows "FORWEAK XS d f c  SPEC (λ(_::unit). True)"
  using assms
  by (intro order_trans[OF FORWEAK_elementwise_rule[where Q=top]])
    (auto simp: top_fun_def le_SPEC_UNIV_rule nofail_SPEC_triv_refine nofail_imp_RES_UNIV)

lemma FORWEAK_mono_rule':
  fixes f::"'d  'e nres" and c::"'e  'e  'e nres" and I::"'d set  'e  bool"
  assumes empty: "S = {}  d  SPEC P"
  assumes I0[THEN order_trans]: "s. s  S  f s  SPEC (I {s})"
  assumes I_mono: "ab bb xb. ab  bb  bb  S  I (insert ab (S - bb)) xb  I (S - bb) xb"
  assumes IP[THEN order_trans]:
    "x it σ.  xS; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I (insert x it)))"
  assumes II: "σ. I S σ  P σ"
  shows "FORWEAK S d f c  SPEC P"
  apply (rule FORWEAK_invarI[where I="λb X. X  S  I (S - X) b"])
  subgoal by (rule empty)
  subgoal by (auto simp: Diff_Diff_Int intro!: I0)
  subgoal
    apply (rule I0, assumption)
    apply (rule SPEC_rule)
    apply (rule conjI)
    subgoal by simp
    subgoal by (rule I_mono, assumption) auto
    done
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: order_trans)
    done
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: I_mono)
    done
  subgoal by (auto intro!: II)
  done

lemma
  op_set_npick_remove_refine_SPEC[refine_vcg]:
  assumes "x X'. x  X1  X' = X1 - {x}  Q (x, X')"
  assumes "x. x  X1  Q (x, X1)"
  shows "op_set_npick_remove X1  SPEC Q"
  using assms
  by (auto simp: op_set_npick_remove_def )

context includes autoref_syntax begin
definition "op_set_pick_remove X  SPEC (λ(x, X'). x  X  X' = X - {x})"
lemma op_set_pick_removepat[autoref_op_pat]:
  "SPEC (λ(x, X'). x  X  X' = X - {x})  op_set_pick_remove $ X"
  "do { x  SPEC (λx. x  X); let X' = X - {x}; f x X' }  do { (x, X')  op_set_pick_remove X; f x X'}"
  by (auto simp: op_set_pick_remove_def pw_eq_iff refine_pw_simps intro!: eq_reflection)

lemma list_all2_tlI: "list_all2 A XS y  list_all2 A (tl XS) (tl y)"
  by (metis list.rel_sel list.sel(2))

lemma
  op_set_pick_remove_refine[autoref_rules]:
  assumes "(XS, X)  Alist_set_rel"
  assumes "SIDE_PRECOND (X  {})"
  shows "(nres_of (dRETURN (hd XS, tl XS)), op_set_pick_remove $ X)  A ×r Alist_set_relnres_rel"
  using assms(1)
  unfolding op_set_pick_remove_def[abs_def] autoref_tag_defs list_set_rel_def list_rel_def br_def
  apply (intro nres_relI SPEC_refine det_SPEC)
  apply safe
  subgoal for x y z
    using assms(2)
    apply (safe intro!: exI[where x="(hd y, set (tl y))"])
    subgoal
      apply (rule prod_relI)
      subgoal by (induct XS y rule: list_all2_induct) auto
      subgoal
        apply (rule relcompI[where b = "tl y"])
        subgoal
          unfolding mem_Collect_eq split_beta' fst_conv snd_conv
          by (rule list_all2_tlI)
        subgoal
          unfolding mem_Collect_eq split_beta' fst_conv snd_conv
          apply (rule conjI)
          subgoal by (metis remove1_tl set_remove1_eq)
          subgoal by simp
          done
        done
      done
    subgoal by (subst (asm) list.rel_sel) simp
    subgoal by (simp add: in_set_tlD)
    subgoal by (simp add: distinct_hd_tl)
    subgoal by auto (meson in_hd_or_tl_conv)
    done
  done

definition [simp, refine_vcg_def]: "isEmpty_spec X = SPEC (λb. b  X = {})"

lemma [autoref_itype]: "isEmpty_spec::i A i i_boolii_nres"
  by simp
lemma op_wset_isEmpty_list_wset_rel[autoref_rules]:
  "(λx. RETURN (x = []), isEmpty_spec)  Alist_wset_rel  bool_relnres_rel"
  by (auto simp: nres_rel_def list_wset_rel_def set_rel_def br_def)


definition WEAK_ALL:: "('a  bool)  'a set  ('a  bool nres)  bool nres" (WEAK'_ALL⇗_) where
  "WEAK_ALL I X P = do {
    (_, b)  WHILE⇗λ(Y, b). b  (x  X - Y. I x)(λ(X, b). b  X  {}) (λ(X, b). do {
      ASSERT (X  {});
      (x, X')  op_set_npick_remove X;
      b'  P x;
      RETURN (X', b'  b)
    }) (X, True); RETURN b}"
schematic_goal WEAK_ALL_list[autoref_rules]:
  assumes [relator_props]: "single_valued A"
  assumes [autoref_rules]: "(Xi, X)  Alist_wset_rel"
      "(P_impl, P)  A  bool_relnres_rel"
  shows "(?r, WEAK_ALL I X P)  bool_relnres_rel"
  unfolding WEAK_ALL_def
  including art
  by (autoref)
concrete_definition WEAK_ALL_list for Xi P_impl uses WEAK_ALL_list
lemma WEAK_ALL_list_refine[autoref_rules]:
  "PREFER single_valued A  (WEAK_ALL_list, WEAK_ALL I)  Alist_wset_rel  (A  bool_relnres_rel)  bool_relnres_rel"
  using WEAK_ALL_list.refine by force

schematic_goal WEAK_ALL_transfer_nres:
  assumes [refine_transfer]: "x. nres_of (f x)  f' x"
  shows "nres_of (?f)  WEAK_ALL_list xs f'"
  unfolding WEAK_ALL_list_def
  by refine_transfer
concrete_definition dWEAK_ALL for xs f uses WEAK_ALL_transfer_nres
lemmas [refine_transfer] = dWEAK_ALL.refine

definition WEAK_EX:: "('a  bool)  'a set  ('a  bool nres)  bool nres" (WEAK'_EX⇗_) where
  "WEAK_EX I X P = do {
    (_, b)  WHILE⇗λ(Y, b). Y  X  (b  (x  X. I x))(λ(X, b). ¬b  X  {}) (λ(X, b). do {
      ASSERT (X  {});
      (x, X')  op_set_npick_remove X;
      b'  P x;
      RETURN (X', b'  b)
    }) (X, False); RETURN b}"
schematic_goal WEAK_EX_list[autoref_rules]:
  assumes [relator_props]: "single_valued A"
  assumes [autoref_rules]: "(Xi, X)  Alist_wset_rel"
      "(P_impl, P)  A  bool_relnres_rel"
  shows "(?r, WEAK_EX I X P)  bool_relnres_rel"
  unfolding WEAK_EX_def
  including art
  by (autoref)
concrete_definition WEAK_EX_list for Xi P_impl uses WEAK_EX_list
lemma WEAK_EX_list_refine[autoref_rules]:
  "PREFER single_valued A  (WEAK_EX_list, WEAK_EX I)  Alist_wset_rel  (A  bool_relnres_rel)  bool_relnres_rel"
  using WEAK_EX_list.refine by force

schematic_goal WEAK_EX_transfer_nres:
  assumes [refine_transfer]: "x. nres_of (f x)  f' x"
  shows "nres_of (?f)  WEAK_EX_list xs f'"
  unfolding WEAK_EX_list_def
  by refine_transfer
concrete_definition dWEAK_EX for xs f uses WEAK_EX_transfer_nres
lemmas [refine_transfer] = dWEAK_EX.refine

lemma WEAK_EX[THEN order_trans, refine_vcg]:
  assumes [THEN order_trans, refine_vcg]: "x. F x  SPEC (λr. r  I x)"
  shows "WEAK_EX I X F  SPEC (λr. r  (xX. I x))"
  unfolding WEAK_EX_def
  by (refine_vcg ) auto

lemma WEAK_ALL[THEN order_trans, refine_vcg]:
  assumes [THEN order_trans, refine_vcg]: "x. F x  SPEC (λr. r  I x)"
  shows "WEAK_ALL I X F  SPEC (λr. r  (xX. I x))"
  unfolding WEAK_ALL_def
  by (refine_vcg) auto

lemma [autoref_op_pat_def]:
  "WEAK_ALL I  OP (WEAK_ALL I)"
  "WEAK_EX I  OP (WEAK_EX I)"
  by auto

lemma list_spec_impl[autoref_rules]:
  "(λx. RETURN x, list_spec)  Alist_wset_rel  Alist_relnres_rel"
  if "PREFER single_valued A"
  using that
  apply (auto simp: list_spec_def nres_rel_def RETURN_RES_refine_iff list_wset_rel_br_eq
      br_list_rel intro!: brI dest!: brD
      elim!: single_valued_as_brE)
  subgoal for a I xs
    apply (rule exI[where x="map a xs"])
    by (auto simp: br_def list_all_iff)
  done

lemma list_wset_autoref_delete[autoref_rules]:
  assumes "PREFER single_valued R"
  assumes "GEN_OP eq (=) (R  R  bool_rel)"
  shows "(λy xs. [xxs. ¬eq y x], op_set_delete)  R  Rlist_wset_rel  Rlist_wset_rel"
  using assms
  apply (auto simp: list_wset_rel_def dest!: brD elim!: single_valued_as_brE)
  apply (rule relcompI)
   apply (rule brI)
    apply (rule refl)
   apply auto
  apply (auto simp: set_rel_br)
  apply (rule brI)
   apply (auto dest!: brD dest: fun_relD)
   apply (auto simp: image_iff dest: fun_relD intro: brI)
  subgoal for a b c d e
    apply (drule spec[where x=e])
    apply auto
    apply (drule fun_relD)
     apply (rule brI[where c="c"])
      apply (rule refl)
     apply assumption
    apply (drule bspec, assumption)
    apply (drule fun_relD)
     apply (rule brI[where c="e"])
      apply (rule refl)
     apply assumption
    apply auto
    done
  done

lemma FORWEAK_mono_rule'':
  fixes f::"'d  'e nres" and c::"'e  'e  'e nres" and I::"'d set  'e  bool"
  assumes empty: "S = {}  d  SPEC P"
  assumes I0[THEN order_trans]: "s. s  S  f s  SPEC (I {s})"
  assumes I_mono: "it it' σ. I it σ  it'  it  it  S  I it' σ"
  assumes IP[THEN order_trans]:
    "x it σ.  xS; x  it; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I (insert x it)))"
  assumes II: "σ. I S σ  P σ"
  shows "FORWEAK S d f c  SPEC P"
  apply (rule FORWEAK_invarI[where I="λb X. X  S  I (S - X) b"])
  subgoal by (rule empty)
  subgoal by (auto simp: Diff_Diff_Int intro!: I0)
  subgoal
    by (metis (mono_tags, lifting) Diff_cancel I0 I_mono Refine_Basic.RES_sng_eq_RETURN iSPEC_rule
        less_eq_nres.simps(2) nres_order_simps(21) subset_insertI subset_refl)
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: order_trans)
    done
  subgoal for a b it
    apply (rule IP[of _ "S - it" b])
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal
      apply clarsimp
      apply (rule order_trans, assumption)
      by (auto simp: it_step_insert_iff intro: I_mono)
    done
  subgoal by (auto intro!: II)
  done

lemma FORWEAK_mono_rule_empty:
  fixes f::"'d  'e nres" and c::"'e  'e  'e nres" and I::"'d set  'e  bool"
  assumes empty: "S = {}  RETURN d  SPEC P"
  assumes I0: "I {} d"
  assumes I1: "s x. s  S  c d x  SPEC (I {s})  I {s} x"
  assumes I_mono: "it it' σ. I it σ  it'  it  it  S  I it' σ"
  assumes II: "σ. I S σ  P σ"
  assumes IP: "x it σ.  xS; x  it; itS; I it σ   f x  SPEC (λf'. c σ f'  SPEC (I (insert x it)))"
  shows "FORWEAK S (RETURN d) f c  SPEC P"
  apply (rule FORWEAK_mono_rule''[where S=S and I=I and P=P])
  subgoal by (rule empty)
  subgoal for s
    apply (rule IP[of _ "{}" d, THEN order_trans])
       apply assumption
       apply force
       apply force
     apply (rule I0)
    by (auto intro!: I1)
  subgoal by (rule I_mono)
  subgoal by (rule IP)
  subgoal by (rule II)
  done

end

end