Theory Prpu_Common_Impl

section ‹Tools for Implementing Push-Relabel Algorithms›
theory Prpu_Common_Impl
imports
  Prpu_Common_Inst
  Flow_Networks.Network_Impl 
  Flow_Networks.NetCheck
begin
  
subsection ‹Basic Operations›
  
type_synonym excess_impl = "node  capacity_impl"  
  
context Network_Impl 
begin  

subsubsection ‹Excess Map›    
text ‹Obtain an excess map with all nodes mapped to zero.›  
definition x_init :: "excess_impl nres" where "x_init  return (λ_. 0)"
text ‹Get the excess of a node.›  
definition x_get :: "excess_impl  node  capacity_impl nres" 
  where "x_get x u  do {
    assert (uV);
    return (x u)
  }"
text ‹Add a capacity to the excess of a node.›    
definition x_add :: "excess_impl  node  capacity_impl  excess_impl nres"  
  where "x_add x u Δ  do {
    assert (uV);
    return (x(u := x u + Δ))
  }"
  
subsubsection ‹Labeling›
text ‹Obtain the initial labeling: All nodes are zero, except the 
  source which is labeled by |V|›. The exact cardinality of V› is passed
  as a parameter.
›  
definition l_init :: "nat  (node  nat) nres"
  where "l_init C  return ((λ_. 0)(s := C))"

text ‹Get the label of a node.›    
definition l_get :: "(node  nat)  node  nat nres"    
  where "l_get l u  do {
    assert (u  V);
    return (l u)
  }"

text ‹Set the label of a node.›    
definition l_set :: "(node  nat)  node  nat  (node  nat) nres"    
  where "l_set l u a  do {
    assert (uV);
    assert (a < 2*card V);
    return (l(u := a))
  }"

subsubsection ‹Label Frequency Counts for Gap Heuristics›
text ‹Obtain the frequency counts for the initial labeling.
  Again, the cardinality of |V|›, which is required to determine the label
  of the source node, is passed as an explicit parameter.
›  
definition cnt_init :: "nat  (nat  nat) nres"
  where "cnt_init C  do {
    assert (C<2*N);
    return ((λ_. 0)(0 := C - 1, C := 1))
  }"

text ‹Get the count for a label value.›    
definition cnt_get :: "(nat  nat)  nat  nat nres"    
  where "cnt_get cnt lv  do {
    assert (lv < 2*N);
    return (cnt lv)
  }"

text ‹Increment the count for a label value by one.›    
definition cnt_incr :: "(nat  nat)  nat  (nat  nat) nres"    
  where "cnt_incr cnt lv  do {
    assert (lv < 2*N);
    return (cnt ( lv := cnt lv + 1 ))
  }"

text ‹Decrement the count for a label value by one.›    
definition cnt_decr :: "(nat  nat)  nat  (nat  nat) nres"    
  where "cnt_decr cnt lv  do {
    assert (lv < 2*N  cnt lv > 0);
    return (cnt ( lv := cnt lv - 1 ))
  }"
    
end ― ‹Network Implementation Locale›  

  
subsection ‹Refinements to Basic Operations›  
  
context Network_Impl 
begin  
text ‹In this section, we refine the algorithm to actually use the 
 basic operations.
›
  
subsubsection ‹Explicit Computation of the Excess›  
definition "xf_rel  { ((excess f,cf_of f),f) | f. True }"
lemma xf_rel_RELATES[refine_dref_RELATES]: "RELATES xf_rel" 
  by (auto simp: RELATES_def)
  
definition "pp_init_x 
   λu. (if u=s then ((u,v)outgoing s. - c(u,v)) else c (s,u))"
  
lemma excess_pp_init_f[simp]: "excess pp_init_f = pp_init_x"  
  apply (intro ext)  
  subgoal for u  
    unfolding excess_def pp_init_f_def pp_init_x_def
    apply (cases "u=s")  
    subgoal
      unfolding outgoing_def incoming_def    
      by (auto intro: sum.cong simp: sum_negf)
    subgoal proof -
      assume [simp]: "us"
      have [simp]: 
        "(case e of (u, v)  if u = s then c (u, v) else 0) = 0" 
        if "eoutgoing u" for e
        using that by (auto simp: outgoing_def)
      have [simp]: "(case e of (u, v)  if u = s then c (u, v) else 0) 
        = (if e = (s,u) then c (s,u) else 0)" 
        if "eincoming u" for e
        using that by (auto simp: incoming_def split: if_splits)
      show ?thesis by (simp add: sum.delta) (simp add: incoming_def)
    qed 
    done  
  done  
    
definition "pp_init_cf 
   λ(u,v). if (v=s) then c (v,u) else if u=s then 0 else c (u,v)"
lemma cf_of_pp_init_f[simp]: "cf_of pp_init_f = pp_init_cf"
  apply (intro ext)  
  unfolding pp_init_cf_def pp_init_f_def residualGraph_def
  using no_parallel_edge  
  by auto  
    
  
lemma pp_init_x_rel: "((pp_init_x, pp_init_cf), pp_init_f)  xf_rel"
  unfolding xf_rel_def by auto

subsubsection ‹Algorithm to Compute Initial Excess and Flow›    
definition "pp_init_xcf2_aux  do {
  let x=(λ_. 0);
  let cf=c;

  foreach (adjacent_nodes s) (λv (x,cf). do {
    assert ((s,v)E);
    assert (s  v);
    let a = cf (s,v);
    assert (x v = 0);
    let x = x( s := x s - a, v := a );
    let cf = cf( (s,v) := 0, (v,s) := a);
    return (x,cf)
  }) (x,cf)
}"
  
lemma pp_init_xcf2_aux_spec: 
  shows "pp_init_xcf2_aux  SPEC (λ(x,cf). x=pp_init_x  cf = pp_init_cf)"
proof -
  have ADJ_S_AUX: "adjacent_nodes s = {v . (s,v)E}"
    unfolding adjacent_nodes_def using no_incoming_s by auto
    
  have CSU_AUX: "c (s,u) = 0" if "uadjacent_nodes s" for u
    using that unfolding adjacent_nodes_def by auto
      
  show ?thesis
    unfolding pp_init_xcf2_aux_def
    apply (refine_vcg FOREACH_rule[where I="λit (x,cf). 
        x s = (vadjacent_nodes s - it. - c(s,v)) 
       (vadjacent_nodes s. x v = (if vit then 0 else c (s,v)))
       (v-insert s (adjacent_nodes s). x v = 0)
       (vadjacent_nodes s. 
            if vit then cf (s,v) = 0  cf (v,s) = c (s,v) 
            else cf (s,v) = c (s,v)  cf (v,s) = c (v,s))
       (u v. us  vs  cf (u,v) = c (u,v) )
       (u. uadjacent_nodes s  cf (u,s) = 0  cf (s,u) = 0)
    "])
    apply (vc_solve simp: it_step_insert_iff simp: CSU_AUX)
    subgoal for v it by (auto simp: ADJ_S_AUX) 
    subgoal for u it _ v by (auto split: if_splits)
    subgoal by (auto simp: ADJ_S_AUX)    
    subgoal by (auto simp: ADJ_S_AUX)    
    subgoal by (auto split: if_splits)    
    (* TODO: This proof is still a bit fragile *)    
    subgoal for x
      unfolding pp_init_x_def
      apply (intro ext)  
      subgoal for u  
        apply (clarsimp simp: ADJ_S_AUX outgoing_def; intro conjI)  
        applyS (auto intro!: sum.reindex_cong[where l=snd] intro: inj_onI)
        applyS (metis (mono_tags, lifting) Compl_iff Graph.zero_cap_simp insertE mem_Collect_eq)  
        done
      done  
    subgoal for x cf    
      unfolding pp_init_cf_def
      apply (intro ext)  
      apply (clarsimp; auto simp: CSU_AUX)
      done  
    done  
qed      
    
definition "pp_init_xcf2 am  do {
  x  x_init;
  cf  cf_init;

  assert (sV);
  adj  am_get am s;
  nfoldli adj (λ_. True) (λv (x,cf). do {
    assert ((s,v)E);
    assert (s  v);
    a  cf_get cf (s,v);
    x  x_add x s (-a);
    x  x_add x v a;
    cf  cf_set cf (s,v) 0; 
    cf  cf_set cf (v,s) a; 
    return (x,cf)
  }) (x,cf)
}"
  
  
lemma pp_init_xcf2_refine_aux:
  assumes AM: "is_adj_map am"  
  shows "pp_init_xcf2 am  Id (pp_init_xcf2_aux)"
  unfolding pp_init_xcf2_def pp_init_xcf2_aux_def
  unfolding x_init_def cf_init_def am_get_def cf_get_def cf_set_def x_add_def  
  apply (simp only: nres_monad_laws)
  supply LFO_refine[OF am_to_adj_nodes_refine[OF AM], refine]
  apply refine_rcg  
  using E_ss_VxV  
  by auto
  
  
lemma pp_init_xcf2_refine[refine2]: 
  assumes AM: "is_adj_map am"  
  shows "pp_init_xcf2 am xf_rel (RETURN pp_init_f)"
  using pp_init_xcf2_refine_aux[OF AM] pp_init_xcf2_aux_spec pp_init_x_rel
  by (auto simp: pw_le_iff refine_pw_simps)  
  
subsubsection ‹Computing the Minimal Adjacent Label›  
definition (in Network) "min_adj_label_aux cf l u  do {
  assert (uV);
  x  foreach (adjacent_nodes u) (λv x. do {
    assert ((u,v)EE¯);
    assert (vV);
    if (cf (u,v)  0) then 
      case x of 
        None  return (Some (l v)) 
      | Some xx  return (Some (min (l v) (xx)))
    else
      return x
  }) None;

  assert (xNone);
  return (the x)
}"
    

lemma (in -) set_filter_xform_aux: 
  "{ f x | x. ( x = a  xS  xit )  P x } 
  = (if P a then {f a} else {})  {f x | x. xS-it  P x}"    
  by auto
    
lemma (in Labeling) min_adj_label_aux_spec: 
  assumes PRE: "relabel_precond f l u"
  shows "min_adj_label_aux cf l u  SPEC (λx. x = Min { l v | v. (u,v)cf.E })"
proof -
  have AUX: "cf (u,v)  0  (u,v)cf.E" for v unfolding cf.E_def by auto
  
  have EQ: "{ l v | v. (u,v)cf.E } 
    = { l v | v. vadjacent_nodes u  cf (u,v)0 }"
    unfolding AUX
    using cfE_ss_invE
    by (auto simp: adjacent_nodes_def)
  
  define Min_option :: "nat set  nat" 
    where "Min_option X  if X={} then None else Some (Min X)" for X
      
  from PRE active_has_cf_outgoing have "cf.outgoing u  {}" 
    unfolding relabel_precond_def by auto
  hence [simp]: "uV" unfolding cf.outgoing_def using cfE_of_ss_VxV by auto
  from cf.outgoing u  {} 
  have AUX2: "v. v  adjacent_nodes u  cf (u, v)  0"
    by (smt AUX Collect_empty_eq Image_singleton_iff UnCI adjacent_nodes_def 
            cf.outgoing_def cf_def converse_iff prod.simps(2))
      
  show ?thesis unfolding min_adj_label_aux_def EQ   
    apply (refine_vcg 
        FOREACH_rule[where 
          I="λit x. x = Min_option 
                          { l v | v. vadjacent_nodes u - it  cf (u,v)0 }"]
        )  
    apply (vc_solve 
        simp: Min_option_def it_step_insert_iff set_filter_xform_aux 
        split: if_splits)
    subgoal unfolding adjacent_nodes_def by auto  
    subgoal unfolding adjacent_nodes_def by auto  
    subgoal using adjacent_nodes_ss_V by auto  
    subgoal using adjacent_nodes_ss_V by auto
    subgoal by (auto simp: Min.insert_remove)
    subgoal using AUX2 by auto
    done    
qed        

definition "min_adj_label am cf l u  do {
  assert (uV);
  adj  am_get am u;
  x  nfoldli adj (λ_. True) (λv x. do {
    assert ((u,v) E  E¯);
    assert (vV);
    cfuv  cf_get cf (u,v);
    if (cfuv  0) then do {
      lv  l_get l v;
      case x of 
        None  return (Some lv) 
      | Some xx  return (Some (min lv xx))
    } else
      return x
  }) None;

  assert (xNone);
  return (the x)
}"

lemma min_adj_label_refine[THEN order_trans, refine_vcg]:
  assumes "Height_Bounded_Labeling c s t f l"
  assumes AM: "(am,adjacent_nodes)nat_relnat_rellist_set_rel"
  assumes PRE: "relabel_precond f l u"
  assumes [simp]: "cf = cf_of f"  
  shows "min_adj_label am cf l u  SPEC (λx. x 
        = Min { l v | v. (u,v)cfE_of f })"  
proof - 
  interpret Height_Bounded_Labeling c s t f l by fact

  have "min_adj_label am (cf_of f) l u  Id (min_adj_label_aux (cf_of f) l u)"  
    unfolding min_adj_label_def min_adj_label_aux_def Let_def
    unfolding am_get_def cf_get_def l_get_def  
    apply (simp only: nres_monad_laws)  
    supply LFO_refine[OF fun_relD[OF AM IdI] _ IdI, refine]
    apply (refine_rcg)
    apply refine_dref_type  
    by auto  
  also note min_adj_label_aux_spec[OF PRE]    
  finally show ?thesis by simp  
qed      

subsubsection ‹Refinement of Relabel›
text ‹Utilities to Implement Relabel Operations›    
    
definition "relabel2 am cf l u  do {
  assert (uV - {s,t});
  nl  min_adj_label am cf l u;
  l  l_set l u (nl+1);
  return l
}"
  
lemma relabel2_refine[refine]: 
  assumes "((x,cf),f)xf_rel"
  assumes AM: "(am,adjacent_nodes)nat_relnat_rellist_set_rel"
  assumes [simplified,simp]: "(li,l)Id" "(ui,u)Id"
  shows "relabel2 am cf li ui  Id (relabel f l u)"    
proof -
  have [simp]: "{l v |v. v  V  cf_of f (u, v)  0} = {l v |v. cf_of f (u, v)  0}"
    using cfE_of_ss_VxV[of f] 
    by (auto simp: Graph.E_def)
  
  show ?thesis
    using assms
    unfolding relabel2_def relabel_def
    unfolding l_set_def
    apply (refine_vcg AM)
    apply (vc_solve (nopre) simp: xf_rel_def relabel_effect_def solve: asm_rl)
    subgoal premises prems for a proof -   
      from prems interpret Height_Bounded_Labeling c s t f l by simp
      interpret l': Height_Bounded_Labeling c s t f "relabel_effect f l u"
        by (rule relabel_pres_height_bound) (rule prems)
      from prems have "uV" by simp
      from prems have "a + 1 = relabel_effect f l u u"
        by (auto simp: relabel_effect_def)
      also note l'.height_bound[THEN bspec, OF uV]
      finally show "a + 1 < 2 * card V" using card_V_ge2 by auto
    qed      
    done
qed
  
subsubsection ‹Refinement of Push›  
definition "push2_aux x cf  λ(u,v). do {
  assert ( (u,v)  E  E¯ );
  assert ( u  v );
  let Δ = min (x u) (cf (u,v));
  return ((x( u := x u - Δ, v := x v + Δ ),augment_edge_cf cf (u,v) Δ))
}"
    
  
lemma push2_aux_refine: 
  "((x,cf),f)xf_rel; (ei,e)Id×rId 
     push2_aux x cf ei  xf_rel (push f l e)"
  unfolding push_def push2_aux_def
  apply refine_vcg  
  apply (vc_solve simp: xf_rel_def no_self_loop)
  subgoal for u v 
    unfolding push_precond_def using cfE_of_ss_invE by auto
  subgoal for u v 
  proof -
    assume [simp]: "Labeling c s t f l"
    then interpret Labeling c s t f l .
    assume "push_precond f l (u, v)"    
    then interpret l': push_effect_locale c s t f l u v by unfold_locales
    show ?thesis 
      apply (safe intro!: ext)
      using l'.excess'_if l'.Δ_def l'.cf'_alt l'.uv_not_eq(1)
      by (auto)  
  qed
  done  

definition "push2 x cf  λ(u,v). do {
  assert ( (u,v)  E  E¯ );
  xu  x_get x u;
  cfuv  cf_get cf (u,v);
  cfvu  cf_get cf (v,u);
  let Δ = min xu cfuv;
  x  x_add x u (-Δ);
  x  x_add x v Δ;

  cf  cf_set cf (u,v) (cfuv - Δ);
  cf  cf_set cf (v,u) (cfvu + Δ);

  return (x,cf)
}"
    
lemma push2_refine[refine]: 
  assumes "((x,cf),f)xf_rel" "(ei,e)Id×rId"
  shows "push2 x cf ei  xf_rel (push f l e)"
proof -
  have "push2 x cf ei  (push2_aux x cf ei)"  
    unfolding push2_def push2_aux_def
    unfolding x_get_def x_add_def cf_get_def cf_set_def
    unfolding augment_edge_cf_def  
    apply (simp only: nres_monad_laws)  
    apply refine_vcg  
    using E_ss_VxV  
    by auto  
  also note push2_aux_refine[OF assms]    
  finally show ?thesis . 
qed  
  
  
  
subsubsection ‹Adding frequency counters to labeling›
      
definition "l_invar l  v. l v  0  vV"  

definition "clc_invar  λ(cnt,l). 
  (lv. cnt lv = card { uV . l u = lv }) 
 (u. l u < 2*N)  l_invar l"
definition "clc_rel  br snd clc_invar"    
    
definition "clc_init C  do {
  l  l_init C;
  cnt  cnt_init C;
  return (cnt,l)
}"
  
definition "clc_get  λ(cnt,l) u. l_get l u"
definition "clc_set  λ(cnt,l) u a. do {
  assert (a<2*N);
  lu  l_get l u;
  cnt  cnt_decr cnt lu;
  l  l_set l u a;
  lu  l_get l u;
  cnt  cnt_incr cnt lu;
  return (cnt,l)
}"  

definition "clc_has_gap  λ(cnt,l) lu. do {
  nlu  cnt_get cnt lu;
  return (nlu = 0)
}"
    
lemma cardV_le_N: "card V  N" using card_mono[OF _ V_ss] by auto
lemma N_not_Z: "N  0" using card_V_ge2 cardV_le_N by auto
lemma N_ge_2: "2N" using card_V_ge2 cardV_le_N by auto
  
lemma clc_init_refine[refine]:
  assumes [simplified,simp]: "(Ci,C)nat_rel" 
  assumes [simp]: "C = card V" 
  shows "clc_init Ci clc_rel (l_init C)"  
proof -
  have AUX: "{u. u  s  u  V} = V-{s}" by auto
  
  show ?thesis
    unfolding clc_init_def l_init_def cnt_init_def
    apply refine_vcg
    unfolding clc_rel_def clc_invar_def
    using cardV_le_N N_not_Z
    by (auto simp: in_br_conv V_not_empty AUX l_invar_def)  
qed  

lemma clc_get_refine[refine]: 
  " (clc,l)clc_rel; (ui,u)nat_rel   clc_get clc ui Id (l_get l u)"
  unfolding clc_get_def clc_rel_def
  by (auto simp: in_br_conv split: prod.split)  

definition l_get_rlx :: "(node  nat)  node  nat nres"    
  where "l_get_rlx l u  do {
    assert (u < N);
    return (l u)
  }"
definition "clc_get_rlx  λ(cnt,l) u. l_get_rlx l u"
  
lemma clc_get_rlx_refine[refine]: 
  " (clc,l)clc_rel; (ui,u)nat_rel  
   clc_get_rlx clc ui Id (l_get_rlx l u)"
  unfolding clc_get_rlx_def clc_rel_def
  by (auto simp: in_br_conv split: prod.split)  
    
lemma card_insert_disjointI: 
  " finite Y; X = insert x Y; xY   card X = Suc (card Y)"    
  by auto
  
lemma clc_set_refine[refine]:
  " (clc,l)  clc_rel; (ui,u)nat_rel; (ai,a)nat_rel  
    clc_set clc ui ai clc_rel (l_set l u a)"
  unfolding clc_set_def l_set_def l_get_def cnt_decr_def cnt_incr_def
  apply refine_vcg  
  apply vc_solve
  unfolding clc_rel_def in_br_conv clc_invar_def l_invar_def
  subgoal using cardV_le_N by auto
  applyS auto  
  applyS (auto simp: simp: card_gt_0_iff)
    
  subgoal for cnt ll 
    apply clarsimp  
    apply (intro impI conjI; clarsimp?)
    subgoal  
      apply (subst le_imp_diff_is_add; simp)
      apply (rule card_insert_disjointI[where x=u])
      by auto
    subgoal     
      apply (rule card_insert_disjointI[where x=u, symmetric])
      by auto
    subgoal
      by (auto intro!: arg_cong[where f=card])
    done
  done    

lemma clc_has_gap_correct[THEN order_trans, refine_vcg]:
  "(clc,l)clc_rel; k<2*N 
   clc_has_gap clc k  (spec r. r  gap_precond l k)"
  unfolding clc_has_gap_def cnt_get_def gap_precond_def
  apply refine_vcg  
  unfolding clc_rel_def clc_invar_def in_br_conv
  by auto  
  
  
    
subsubsection ‹Refinement of Gap-Heuristics›
text ‹Utilities to Implement Gap-Heuristics›    
    
definition "gap_aux C l k  do {
  nfoldli [0..<N] (λ_. True) (λv l. do {
    lv  l_get_rlx l v;
    if (k < lv  lv < C) then do {
      assert (C+1 < 2*N);
      l  l_set l v (C+1);
      return l
    } else return l
  }) l
}"
  
lemma gap_effect_invar[simp]: "l_invar l  l_invar (gap_effect l k)"   
  unfolding gap_effect_def l_invar_def
  by auto  
  
lemma relabel_effect_invar[simp]: "l_invar l; uV  l_invar (relabel_effect f l u)"    
  unfolding relabel_effect_def l_invar_def by auto
    
lemma gap_aux_correct[THEN order_trans, refine_vcg]: 
  "l_invar l; C=card V  gap_aux C l k  SPEC (λr. r=gap_effect l k)"
  unfolding gap_aux_def l_get_rlx_def l_set_def
  apply (simp only: nres_monad_laws)  
  apply (refine_vcg nfoldli_rule[where I = "λit1 it2 l'. u. if uset it2 then l' u = l u else l' u = gap_effect l k u"])
  apply (vc_solve simp: upt_eq_lel_conv)
  subgoal
    apply (frule gap_effect_invar[where k=k])
    unfolding l_invar_def using V_ss by force 
  subgoal using N_not_Z cardV_le_N by auto
  subgoal unfolding l_invar_def by auto  
  subgoal unfolding gap_effect_def by auto
  subgoal for v l' u
    apply (drule spec[where x=u])
    by (auto split: if_splits simp: gap_effect_def)
  subgoal by auto
  done  
    
definition "gap2 C clc k  do {
  nfoldli [0..<N] (λ_. True) (λv clc. do {
    lv  clc_get_rlx clc v;
    if (k < lv  lv < C) then do {
      clc  clc_set clc v (C+1);
      return clc
    } else return clc
  }) clc
}"
    
lemma gap2_refine[refine]:  
  assumes [simplified,simp]: "(Ci,C)nat_rel" "(ki,k)nat_rel"
  assumes CLC: "(clc,l)clc_rel"  
  shows "gap2 Ci clc ki clc_rel (gap_aux C l k)"
  unfolding gap2_def gap_aux_def  
  apply (refine_rcg CLC)
  apply refine_dref_type  
  by auto    
    
  
definition "gap_relabel_aux C f l u  do {
  lu  l_get l u;
  l  relabel f l u;
  if gap_precond l lu then 
    gap_aux C l lu
  else return l
}"  

lemma gap_relabel_aux_refine: 
  assumes [simp]: "C = card V" "l_invar l"
  shows "gap_relabel_aux C f l u  gap_relabel f l u"  
  unfolding gap_relabel_aux_def gap_relabel_def relabel_def 
    gap_relabel_effect_def l_get_def
  apply (simp only: Let_def nres_monad_laws)  
  apply refine_vcg  
  by auto  
    
    
    
definition "min_adj_label_clc am cf clc u  case clc of (_,l)  min_adj_label am cf l u"
    
definition "clc_relabel2 am cf clc u  do {
  assert (uV - {s,t});
  nl  min_adj_label_clc am cf clc u;
  clc  clc_set clc u (nl+1);
  return clc
}"
    
lemma clc_relabel2_refine[refine]: 
  assumes XF: "((x,cf),f)xf_rel"
  assumes CLC: "(clc,l)clc_rel"  
  assumes AM: "(am,adjacent_nodes)nat_relnat_rellist_set_rel"
  assumes [simplified,simp]: "(ui,u)Id"
  shows "clc_relabel2 am cf clc ui  clc_rel (relabel f l u)"    
proof -
  have "clc_relabel2 am cf clc ui clc_rel (relabel2 am cf l ui)"
    unfolding clc_relabel2_def relabel2_def
    apply (refine_rcg)
    apply (refine_dref_type)  
    apply (vc_solve simp: CLC)
    subgoal 
      using CLC 
      unfolding clc_rel_def in_br_conv min_adj_label_clc_def 
      by (auto split: prod.split)
    done    
  also note relabel2_refine[OF XF AM, of l l ui u]
  finally show ?thesis by simp  
qed  
  
  
definition "gap_relabel2 C am cf clc u  do {
  lu  clc_get clc u;
  clc  clc_relabel2 am cf clc u;
  has_gap  clc_has_gap clc lu;
  if has_gap then gap2 C clc lu
  else 
    RETURN clc
}"  
  
lemma gap_relabel2_refine_aux:
  assumes XCF: "((x, cf), f)  xf_rel"  
  assumes CLC: "(clc,l)clc_rel"  
  assumes AM: "(am,adjacent_nodes)nat_relnat_rellist_set_rel"
  assumes [simplified,simp]: "(Ci,C)Id" "(ui,u)Id"
  shows "gap_relabel2 Ci am cf clc ui  clc_rel (gap_relabel_aux C f l u)"  
  unfolding gap_relabel2_def gap_relabel_aux_def
  apply (refine_vcg XCF AM CLC if_bind_cond_refine bind_refine')
  apply (vc_solve solve: refl )
  subgoal for _ lu
    using CLC
    unfolding clc_get_def l_get_def clc_rel_def in_br_conv clc_invar_def
    by (auto simp: refine_pw_simps split: prod.splits)
  done    
    
lemma gap_relabel2_refine[refine]:
  assumes XCF: "((x, cf), f)  xf_rel"  
  assumes CLC: "(clc,l)clc_rel"  
  assumes AM: "(am,adjacent_nodes)nat_relnat_rellist_set_rel"
  assumes [simplified,simp]: "(ui,u)Id"    
  assumes CC: "C = card V"  
  shows "gap_relabel2 C am cf clc ui clc_rel (gap_relabel f l u)"
proof -
  from CLC have LINV: "l_invar l" unfolding clc_rel_def in_br_conv clc_invar_def by auto
  
  note gap_relabel2_refine_aux[OF XCF CLC AM IdI IdI]
  also note gap_relabel_aux_refine[OF CC LINV]  
  finally show ?thesis by simp  
qed    
    
    
subsection ‹Refinement to Efficient Data Structures›  
  
subsubsection ‹Registration of Abstract Operations›  
text ‹We register all abstract operations at once, 
  auto-rewriting the capacity matrix type›
  
context includes Network_Impl_Sepref_Register 
begin  
sepref_register x_get x_add
  
sepref_register l_init l_get l_get_rlx l_set

sepref_register clc_init clc_get clc_set clc_has_gap clc_get_rlx  
  
sepref_register cnt_init cnt_get cnt_incr cnt_decr  
sepref_register gap2 min_adj_label min_adj_label_clc 
  
sepref_register push2 relabel2 clc_relabel2 gap_relabel2
  
sepref_register pp_init_xcf2  
  
end ― ‹Anonymous Context› 
  
  
subsubsection ‹Excess by Array›  
definition "x_assn  is_nf N (0::capacity_impl)"    
  
lemma x_init_hnr[sepref_fr_rules]: 
  "(uncurry0 (Array.new N 0), uncurry0 x_init)  unit_assnk a x_assn"  
  apply sepref_to_hoare unfolding x_assn_def x_init_def 
  by (sep_auto heap: nf_init_rule)
    
lemma x_get_hnr[sepref_fr_rules]: 
  "(uncurry Array.nth, uncurry (PR_CONST x_get)) 
   x_assnk *a node_assnk a cap_assn"
  apply sepref_to_hoare 
  unfolding x_assn_def x_get_def by (sep_auto simp: refine_pw_simps)
    
definition (in -) "x_add_impl x u Δ  do {
  xu  Array.nth x u;
  x  Array.upd u (xu+Δ) x;
  return x
}"  
lemma x_add_hnr[sepref_fr_rules]: 
  "(uncurry2 x_add_impl, uncurry2 (PR_CONST x_add)) 
   x_assnd *a node_assnk *a cap_assnk a x_assn"  
  apply sepref_to_hoare 
  unfolding x_assn_def x_add_impl_def x_add_def 
  by (sep_auto simp: refine_pw_simps)

subsubsection ‹Labeling by Array›      
definition "l_assn  is_nf N (0::nat)"    
definition (in -) "l_init_impl N s cardV  do {
  l  Array.new N (0::nat);
  l  Array.upd s cardV l;
  return l
}"  
lemma l_init_hnr[sepref_fr_rules]: 
  "(l_init_impl N s, (PR_CONST l_init))  nat_assnk a l_assn"  
  apply sepref_to_hoare 
  unfolding l_assn_def l_init_def l_init_impl_def 
  by (sep_auto heap: nf_init_rule)
    
lemma l_get_hnr[sepref_fr_rules]: 
  "(uncurry Array.nth, uncurry (PR_CONST l_get)) 
   l_assnk *a node_assnk a nat_assn"
  apply sepref_to_hoare 
  unfolding l_assn_def l_get_def by (sep_auto simp: refine_pw_simps)
    
lemma l_get_rlx_hnr[sepref_fr_rules]: 
  "(uncurry Array.nth, uncurry (PR_CONST l_get_rlx)) 
   l_assnk *a node_assnk a nat_assn"
  apply sepref_to_hoare 
  unfolding l_assn_def l_get_rlx_def by (sep_auto simp: refine_pw_simps)
    
    
lemma l_set_hnr[sepref_fr_rules]: 
  "(uncurry2 (λa i x. Array.upd i x a), uncurry2 (PR_CONST l_set)) 
   l_assnd *a node_assnk *a nat_assnk a l_assn"
  apply sepref_to_hoare 
  unfolding l_assn_def l_set_def 
  by (sep_auto simp: refine_pw_simps split: prod.split)
      
    
subsubsection ‹Label Frequency by Array›  
  
definition "cnt_assn (f::nodenat) a 
   Al. aal * (length l = 2*N  (i<2*N. l!i = f i)  (i2*N. f i = 0))"
  
definition (in -) "cnt_init_impl N C  do {
  a  Array.new (2*N) (0::nat);
  a  Array.upd 0 (C-1) a;
  a  Array.upd C 1 a;
  return a
}"  

definition (in -) "cnt_incr_impl a k  do {
  freq  Array.nth a k;
  a  Array.upd k (freq+1) a;
  return a
}"  

definition (in -) "cnt_decr_impl a k  do {
  freq  Array.nth a k;
  a  Array.upd k (freq-1) a;
  return a
}"  
  
 
lemma cnt_init_hnr[sepref_fr_rules]: "(cnt_init_impl N, PR_CONST cnt_init)  nat_assnk a cnt_assn"
  apply sepref_to_hoare
  unfolding cnt_init_def cnt_init_impl_def cnt_assn_def
  by (sep_auto simp: refine_pw_simps) 

lemma cnt_get_hnr[sepref_fr_rules]: "(uncurry Array.nth, uncurry (PR_CONST cnt_get))  cnt_assnk *a nat_assnk a nat_assn"    
  apply sepref_to_hoare
  unfolding cnt_get_def cnt_assn_def
  by (sep_auto simp: refine_pw_simps) 

lemma cnt_incr_hnr[sepref_fr_rules]: "(uncurry cnt_incr_impl, uncurry (PR_CONST cnt_incr))  cnt_assnd *a nat_assnk a cnt_assn"    
  apply sepref_to_hoare
  unfolding cnt_incr_def cnt_incr_impl_def cnt_assn_def
  by (sep_auto simp: refine_pw_simps) 
    
lemma cnt_decr_hnr[sepref_fr_rules]: "(uncurry cnt_decr_impl, uncurry (PR_CONST cnt_decr))  cnt_assnd *a nat_assnk a cnt_assn"    
  apply sepref_to_hoare
  unfolding cnt_decr_def cnt_decr_impl_def cnt_assn_def
  by (sep_auto simp: refine_pw_simps) 
  
    
subsubsection ‹Combined Frequency Count and Labeling›    
definition "clc_assn  cnt_assn ×a l_assn"
    

sepref_thm clc_init_impl is "PR_CONST clc_init" :: "nat_assnk a clc_assn" 
  unfolding clc_init_def PR_CONST_def clc_assn_def
  by sepref  
concrete_definition (in -) clc_init_impl 
  uses Network_Impl.clc_init_impl.refine_raw
lemmas [sepref_fr_rules] = clc_init_impl.refine[OF Network_Impl_axioms]
    
sepref_thm clc_get_impl is "uncurry (PR_CONST clc_get)" 
  :: "clc_assnk *a node_assnk a nat_assn" 
  unfolding clc_get_def PR_CONST_def clc_assn_def
  by sepref  
concrete_definition (in -) clc_get_impl 
  uses Network_Impl.clc_get_impl.refine_raw is "(uncurry ?f,_)_"
lemmas [sepref_fr_rules] = clc_get_impl.refine[OF Network_Impl_axioms]
  
sepref_thm clc_get_rlx_impl is "uncurry (PR_CONST clc_get_rlx)" 
  :: "clc_assnk *a node_assnk a nat_assn" 
  unfolding clc_get_rlx_def PR_CONST_def clc_assn_def
  by sepref  
concrete_definition (in -) clc_get_rlx_impl 
  uses Network_Impl.clc_get_rlx_impl.refine_raw is "(uncurry ?f,_)_"
lemmas [sepref_fr_rules] = clc_get_rlx_impl.refine[OF Network_Impl_axioms]
  
  
sepref_thm clc_set_impl is "uncurry2 (PR_CONST clc_set)" 
  :: "clc_assnd *a node_assnk *a nat_assnk a clc_assn" 
  unfolding clc_set_def PR_CONST_def clc_assn_def
  by sepref  
concrete_definition (in -) clc_set_impl 
  uses Network_Impl.clc_set_impl.refine_raw is "(uncurry2 ?f,_)_"
lemmas [sepref_fr_rules] = clc_set_impl.refine[OF Network_Impl_axioms]
  
sepref_thm clc_has_gap_impl is "uncurry (PR_CONST clc_has_gap)" 
  :: "clc_assnk *a nat_assnk a bool_assn" 
  unfolding clc_has_gap_def PR_CONST_def clc_assn_def
  by sepref  
concrete_definition (in -) clc_has_gap_impl 
  uses Network_Impl.clc_has_gap_impl.refine_raw is "(uncurry ?f,_)_"
lemmas [sepref_fr_rules] = clc_has_gap_impl.refine[OF Network_Impl_axioms]
    
    
subsubsection ‹Push›   

sepref_thm push_impl is "uncurry2 (PR_CONST push2)" 
  :: "x_assnd *a cf_assnd *a edge_assnk a (x_assn×acf_assn)" 
  unfolding push2_def PR_CONST_def
  by sepref  
concrete_definition (in -) push_impl 
  uses Network_Impl.push_impl.refine_raw is "(uncurry2 ?f,_)_"
lemmas [sepref_fr_rules] = push_impl.refine[OF Network_Impl_axioms]

subsubsection ‹Relabel›   
sepref_thm min_adj_label_impl is "uncurry3 (PR_CONST min_adj_label)" 
  :: "am_assnk *a cf_assnk *a l_assnk *a node_assnk a nat_assn"  
  unfolding min_adj_label_def PR_CONST_def
  by sepref  
concrete_definition (in -) min_adj_label_impl 
  uses Network_Impl.min_adj_label_impl.refine_raw is "(uncurry3 ?f,_)_"
lemmas [sepref_fr_rules] = min_adj_label_impl.refine[OF Network_Impl_axioms]    
  

sepref_thm relabel_impl is "uncurry3 (PR_CONST relabel2)" 
  :: "am_assnk *a cf_assnk *a l_assnd *a node_assnk a l_assn" 
  unfolding relabel2_def PR_CONST_def
  by sepref  
concrete_definition (in -) relabel_impl 
  uses Network_Impl.relabel_impl.refine_raw is "(uncurry3 ?f,_)_"
lemmas [sepref_fr_rules] = relabel_impl.refine[OF Network_Impl_axioms]
  
subsubsection ‹Gap-Relabel›   
  
sepref_thm gap_impl is "uncurry2 (PR_CONST gap2)" 
  :: "nat_assnk *a clc_assnd *a nat_assnk a clc_assn" 
  unfolding gap2_def PR_CONST_def
  by sepref  
concrete_definition (in -) gap_impl 
  uses Network_Impl.gap_impl.refine_raw is "(uncurry2 ?f,_)_"
lemmas [sepref_fr_rules] = gap_impl.refine[OF Network_Impl_axioms]

sepref_thm min_adj_label_clc_impl is "uncurry3 (PR_CONST min_adj_label_clc)" 
  :: "am_assnk *a cf_assnk *a clc_assnk *a nat_assnk a nat_assn" 
  unfolding min_adj_label_clc_def PR_CONST_def clc_assn_def
  by sepref    
    
concrete_definition (in -) min_adj_label_clc_impl 
  uses Network_Impl.min_adj_label_clc_impl.refine_raw is "(uncurry3 ?f,_)_"
lemmas [sepref_fr_rules] = min_adj_label_clc_impl.refine[OF Network_Impl_axioms]
  
sepref_thm clc_relabel_impl is "uncurry3 (PR_CONST clc_relabel2)" 
    :: "am_assnk *a cf_assnk *a clc_assnd *a node_assnk a clc_assn" 
  unfolding clc_relabel2_def PR_CONST_def
  by sepref  
concrete_definition (in -) clc_relabel_impl 
  uses Network_Impl.clc_relabel_impl.refine_raw is "(uncurry3 ?f,_)_"
lemmas [sepref_fr_rules] = clc_relabel_impl.refine[OF Network_Impl_axioms]
  
sepref_thm gap_relabel_impl is "uncurry4 (PR_CONST gap_relabel2)" 
    :: "nat_assnk *a am_assnk *a cf_assnk *a clc_assnd *a node_assnk 
      a clc_assn" 
  unfolding gap_relabel2_def PR_CONST_def
  by sepref  
concrete_definition (in -) gap_relabel_impl 
  uses Network_Impl.gap_relabel_impl.refine_raw is "(uncurry4 ?f,_)_"
lemmas [sepref_fr_rules] = gap_relabel_impl.refine[OF Network_Impl_axioms]
  
subsubsection ‹Initialization›  
sepref_thm pp_init_xcf2_impl is "(PR_CONST pp_init_xcf2)" 
    :: "am_assnk a x_assn ×a cf_assn" 
  unfolding pp_init_xcf2_def PR_CONST_def
  by sepref
concrete_definition (in -) pp_init_xcf2_impl 
  uses Network_Impl.pp_init_xcf2_impl.refine_raw is "(?f,_)_"
lemmas [sepref_fr_rules] = pp_init_xcf2_impl.refine[OF Network_Impl_axioms]
  
  
end ― ‹Network Implementation Locale›  
  
  
  
  
end