Theory Restrict_Frees_Impl

(*<*)
theory Restrict_Frees_Impl
imports
  Restrict_Bounds_Impl
  Restrict_Frees
begin
(*>*)

section ‹Refining the Non-Deterministic @{term simplification.split} Function›

definition "fixfree_impl 𝒬 = map (apsnd set) (filter (λ(Q, _ :: (nat × nat) list). ∃x ∈ fv Q. gen_impl x Q = [])
   (sorted_list_of_set ((apsnd sorted_list_of_set) ` 𝒬)))"

definition "nongens_impl Q = filter (λx. gen_impl x Q = []) (sorted_list_of_set (fv Q))"

lemma set_nongens_impl: "set (nongens_impl Q) = nongens Q"
  by (auto simp: nongens_def nongens_impl_def set_gen_impl simp flip: List.set_empty)

lemma set_fixfree_impl: "finite 𝒬 ⟹ ∀(_, Qeq) ∈ 𝒬. finite Qeq ⟹ set (fixfree_impl 𝒬) = fixfree 𝒬"
  by (fastforce simp: fixfree_def nongens_def fixfree_impl_def set_gen_impl image_iff apsnd_def map_prod_def
    simp flip: List.set_empty split: prod.splits intro: exI[of _ "sorted_list_of_set _"])

lemma fixfree_empty_iff: "finite 𝒬 ⟹ ∀(_, Qeq) ∈ 𝒬. finite Qeq ⟹ fixfree 𝒬 ≠ {} ⟷ fixfree_impl 𝒬 ≠ []"
  by (auto simp: set_fixfree_impl dest: arg_cong[of _ _ set] simp flip: List.set_empty)

definition "inf_impl 𝒬fin Q =
  map (apsnd set) (filter (λ(Qfix, xys). disjointvars Qfix (set xys) ≠ {} ∨ fv Qfix ∪ Field (set xys) ≠ fv Q)
    (sorted_list_of_set ((apsnd sorted_list_of_set) ` 𝒬fin)))"

lemma set_inf_impl: "finite 𝒬fin ⟹ ∀(_, Qeq) ∈ 𝒬fin. finite Qeq ⟹ set (inf_impl 𝒬fin Q) = inf 𝒬fin Q"
  by (fastforce simp: inf_def inf_impl_def image_iff)

lemma inf_empty_iff: "finite 𝒬fin ⟹ ∀(_, Qeq) ∈ 𝒬fin. finite Qeq ⟹ inf 𝒬fin Q ≠ {} ⟷ inf_impl 𝒬fin Q ≠ []"
  by (auto simp: set_inf_impl dest: arg_cong[of _ _ set] simp flip: List.set_empty)

definition (in simplification) split_impl :: "('a :: {infinite, linorder}, 'b :: linorder) fmla ⇒ (('a, 'b) fmla × ('a, 'b) fmla) nres" where
  "split_impl Q = do {
     Q' ← rb_impl Q;
     𝒬pair ← WHILE
        (λ(𝒬fin, _). fixfree_impl 𝒬fin ≠ []) (λ(𝒬fin, 𝒬inf). do {
          (Qfix, Qeq) ← RETURN (hd (fixfree_impl 𝒬fin));
          x ← RETURN (hd (nongens_impl Qfix));
          G ← RETURN (hd (cov_impl x Qfix));
          let 𝒬fin = 𝒬fin - {(Qfix, Qeq)} ∪
            {(simp (Conj Qfix (DISJ (qps G))), Qeq)} ∪
            (⋃y ∈ eqs x G. {(cp (Qfix[x → y]), Qeq ∪ {(x,y)})});
          let 𝒬inf = 𝒬inf ∪ {cp (Qfix ⊥ x)};
          RETURN (𝒬fin, 𝒬inf)})
        ({(Q', {})}, {});
     𝒬pair ← WHILE
        (λ(𝒬fin, _). inf_impl 𝒬fin Q ≠ []) (λ(𝒬fin, 𝒬inf). do {
          Qpair ← RETURN (hd (inf_impl 𝒬fin Q));
          let 𝒬fin = 𝒬fin - {Qpair};
          let 𝒬inf = 𝒬inf ∪ {CONJ Qpair};
          RETURN (𝒬fin, 𝒬inf)})
        𝒬pair;
     let (Qfin, Qinf) = assemble 𝒬pair;
     Qinf ← rb_impl Qinf;
     RETURN (Qfin, Qinf)}"

lemma (in simplification) split_INV2_imp_split_INV1: "split_INV2 Q 𝒬pair ⟹ split_INV1 Q 𝒬pair"
  unfolding split_INV1_def split_INV2_def wf_state_def sr_def by auto

lemma hd_fixfree_impl_props:
  assumes "finite 𝒬" "∀(_, Qeq) ∈ 𝒬. finite Qeq" "fixfree_impl 𝒬 ≠ []"
  shows "hd (fixfree_impl 𝒬) ∈ 𝒬" "nongens (fst (hd (fixfree_impl 𝒬))) ≠ {}"
proof -
  from hd_in_set[of "fixfree_impl 𝒬"] assms(3) have "hd (fixfree_impl 𝒬) ∈ set (fixfree_impl 𝒬)"
    by blast
  then have "hd (fixfree_impl 𝒬) ∈ fixfree 𝒬"
    by (auto simp: set_fixfree_impl assms(1,2))
  then show "hd (fixfree_impl 𝒬) ∈ 𝒬" "nongens (fst (hd (fixfree_impl 𝒬))) ≠ {}"
    unfolding fixfree_def by auto
qed

lemma (in simplification) split_impl_refines_split: "split_impl Q ≤ split Q"
  apply (unfold split_def split_impl_def Let_def)
  supply rb_impl_refines_rb[refine_mono]
  apply refine_mono
   apply (rule order_trans[OF WHILE_le_WHILEI[where I="split_INV1 Q"]])
   apply (rule order_trans[OF WHILEI_le_WHILEIT])
   apply (rule WHILEIT_refine[OF _ _ _ refine_IdI, THEN refine_IdD])
      apply (simp_all only: pair_in_Id_conv split: prod.splits) [4]
    apply (intro allI impI, hypsubst_thin)
    apply (subst fixfree_empty_iff; auto simp: split_INV1_def wf_state_def)
    apply (intro allI impI, simp only: prod.inject, elim conjE, hypsubst_thin)
   apply refine_mono
  apply (subst set_fixfree_impl[symmetric]; auto simp: split_INV1_def wf_state_def intro!: hd_in_set)
  apply clarsimp
  subgoal for Q' 𝒬fin 𝒬inf Qfix Qeq Qfix' Qeq'
    using hd_fixfree_impl_props(2)[of 𝒬fin]
    by (force simp: split_INV1_def wf_state_def set_nongens_impl[symmetric] dest!: sym[of "(Qfix', _)"] intro!: hd_in_set)
   apply clarsimp
  subgoal for Q' 𝒬fin 𝒬inf Qfix Qeq Qfix' Qeq'
    apply (intro RETURN_rule cov_impl_cov hd_in_set rrb_cov_impl)
    using hd_fixfree_impl_props(1)[of 𝒬fin]
    by (force simp: split_INV1_def wf_state_def dest!: sym[of "(Qfix', _)"])
   apply (rule order_trans[OF WHILE_le_WHILEI[where I="split_INV1 Q"]])
   apply (rule order_trans[OF WHILEI_le_WHILEIT])
  apply (rule WHILEIT_refine[OF _ _ _ refine_IdI, THEN refine_IdD])
     apply (simp_all only: pair_in_Id_conv split_INV2_imp_split_INV1 split: prod.splits) [4]
   apply (intro allI impI, simp only: prod.inject, elim conjE, hypsubst_thin)
   apply (subst inf_empty_iff; auto simp: split_INV2_def wf_state_def)
  apply (intro allI impI, simp only: prod.inject, elim conjE, hypsubst_thin)
  apply refine_mono
  apply (subst set_inf_impl[symmetric]; auto simp: split_INV2_def wf_state_def intro!: hd_in_set)
  done

definition (in simplification) split_impl_det :: "('a :: {infinite, linorder}, 'b :: linorder) fmla ⇒ (('a, 'b) fmla × ('a, 'b) fmla) dres" where
  "split_impl_det Q = do {
     Q' ← rb_impl_det Q;
     𝒬pair ← dWHILE
        (λ(𝒬fin, _). fixfree_impl 𝒬fin ≠ []) (λ(𝒬fin, 𝒬inf). do {
          (Qfix, Qeq) ← dRETURN (hd (fixfree_impl 𝒬fin));
          x ← dRETURN (hd (nongens_impl Qfix));
          G ← dRETURN (hd (cov_impl x Qfix));
          let 𝒬fin = 𝒬fin - {(Qfix, Qeq)} ∪
            {(simp (Conj Qfix (DISJ (qps G))), Qeq)} ∪
            (⋃y ∈ eqs x G. {(cp (Qfix[x → y]), Qeq ∪ {(x,y)})});
          let 𝒬inf = 𝒬inf ∪ {cp (Qfix ⊥ x)};
          dRETURN (𝒬fin, 𝒬inf)})
        ({(Q', {})}, {});
     𝒬pair ← dWHILE
        (λ(𝒬fin, _). inf_impl 𝒬fin Q ≠ []) (λ(𝒬fin, 𝒬inf). do {
          Qpair ← dRETURN (hd (inf_impl 𝒬fin Q));
          let 𝒬fin = 𝒬fin - {Qpair};
          let 𝒬inf = 𝒬inf ∪ {CONJ Qpair};
          dRETURN (𝒬fin, 𝒬inf)})
        𝒬pair;
     let (Qfin, Qinf) = assemble 𝒬pair;
     Qinf ← rb_impl_det Qinf;
     dRETURN (Qfin, Qinf)}"

lemma (in simplification) split_impl_det_refines_split_impl: "nres_of (split_impl_det Q) ≤ split_impl Q"
  unfolding split_impl_def split_impl_det_def Let_def
  by (refine_transfer rb_impl_det_refines_rb_impl)

lemmas (in simplification) SPLIT_correct =
  split_impl_det_refines_split_impl[THEN order_trans, OF
  split_impl_refines_split[THEN order_trans, OF
  split_correct]]

(*<*)
end
(*>*)