Theory SeprefUF

section ‹Union Find in Sepref›

theory SeprefUF
imports Refine_Imperative_HOL.Sepref "Separation_Logic_Imperative_HOL.Union_Find"
begin

(* TODO:  move to sepref/IICF *)

  type_synonym 'a per = "('a×'a) set"


  definition "per_init D  {(i,i) | i. iD}"
  definition [simp]: "per_compare R a b  (a,b)R"

  definition per_init' :: "nat  nat per" where "per_init' n  {(i,i) |i. i<n}"

  lemma per_init_of_nat_range: "per_init {i. i<N} = per_init' N"
    by (auto simp: per_init_def per_init'_def)

  lemma per_init_per[simp, intro!]:
    "part_equiv (per_init D)"
    unfolding per_init_def
    by (auto simp: part_equiv_def sym_def trans_def)

  lemma per_init_self: "(a,b)per_init D  a=b"
    unfolding per_init_def by simp

  lemma per_union_impl: "(i,j)R  (i,j)per_union R a b"
    by (auto simp: per_union_def)

  lemma per_union_related:
    "part_equiv R  aDomain R  bDomain  R  (a,b)per_union R a b"
    unfolding per_union_def
    by (auto simp: part_equiv_refl)

  lemma part_equiv_refl':
    "part_equiv R  xDomain R  (x,x)R"
    using part_equiv_refl[of R x] by blast


  definition per_supset_rel :: "('a per × 'a per) set" where
    "per_supset_rel
       {(p1,p2). p1  Domain p2 × Domain p2 = p2  p1 - (Domain p2 × Domain p2)  Id}"

  lemma per_supset_rel_dom: "(p1, p2)  per_supset_rel  Domain p1  Domain p2"
    by (auto simp: per_supset_rel_def)
  
  lemma per_supset_compare:
    "(p1, p2)  per_supset_rel  x1Domain p2  x2Domain p2  per_compare p1 x1 x2  per_compare p2 x1 x2"
    by (auto simp: per_supset_rel_def)
  
  lemma per_supset_union: "(p1, p2)  per_supset_rel  x1Domain p2  x2Domain p2 
    (per_union p1 x1 x2, per_union p2 x1 x2)  per_supset_rel"
    apply (clarsimp simp: per_supset_rel_def per_union_def Domain_unfold )
    apply (intro subsetI conjI)
     apply blast
    apply force
    done


  sepref_register per_init per_init' per_compare per_union

  lemma per_init_Domain[simp]: "Domain (per_init D) = D"
    by (auto simp: per_init_def)

  lemma per_init'_Domain[simp]: "Domain (per_init' N) = {i. i<N}"
    by (auto simp: per_init'_def)


  lemma per_init'_sepref_rule[sepref_fr_rules]: "(uf_init,RETURN o per_init')  nat_assnk a is_uf"
    unfolding per_init'_def
    apply sepref_to_hoare
    by sep_auto

  lemma per_compare_sepref_rule[sepref_fr_rules]: "(uncurry2 uf_cmp, uncurry2 (RETURN ooo per_compare)) 
    is_ufk *a nat_assnk *a nat_assnk a bool_assn"
    unfolding per_compare_def
    apply sepref_to_hoare
    by sep_auto

  lemma per_union_sepref_rule[sepref_fr_rules]: "(uncurry2 uf_union, uncurry2 (RETURN ooo per_union)) 
    [λ((R,i),j). iDomain R  jDomain R ]a is_ufd *a nat_assnk *a nat_assnk  is_uf"
    unfolding per_compare_def
    apply sepref_to_hoare
    by sep_auto



  definition "abs_test  do {
    let u = per_init' (5::nat);
    let u = per_union u 1 2;
    let u = per_union u 2 3;
    RETURN (per_compare u 1 3)
  }"

  sepref_definition abs_test_impl is "uncurry0 abs_test" :: "unit_assnk a bool_assn"
    unfolding abs_test_def
    by sepref

end