Theory DFS_Framework.General_DFS_Structure

section ‹Generic DFS and Refinement›
theory General_DFS_Structure
imports "../../Param_DFS"
begin
text ‹
  We define the generic structure of DFS algorithms, 
  and use this to define a notion of refinement between DFS algorithms.
›


(*        Generic plot: 
          Define generic DFS-scheme (paramDFS is instance)
          Make basic assumptions on DFS scheme parameters: 
            discovered increasing, new_root_discovered, …
          Show how to implement scheme by FOREACH/WHILE, etc
          This gives a generic implementation for all things that follow basic DFS scheme

          Then define simplified DFS-variants (using general DFS scheme): 
            With on-stack, without on-stack
          Also refine without on-stack to restriction (?)

          Orthogonal refinements:
            1. Refine algorithmic structure, operations remain the same: i.e. fe_impl, rec_impl, ...
            2. Refine operations, structure remains the same:
                 Special case: Refine operations while keeping parametrization
*)


named_theorems DFS_code_unfold ‹DFS framework: Unfolding theorems to prepare term for automatic refinement›
(*ML {*
  structure DFS_code_unfold = Named_Thms (
    val name = @{binding DFS_code_unfold}
    val description = "DFS framework: Unfolding theorems to prepare term for automatic refinement"
  )
*}
setup DFS_code_unfold.setup*)

(* Basic setup *)
lemmas [DFS_code_unfold] = 
  REC_annot_def (* TODO: Setup REC_annot for autoref!*)
  GHOST_elim_Let (* TODO: Unfold in autoref. Can we (ab)use autoref_op_pat_def for that *)
  comp_def (* TODO: Setup transfer package to handle this ((RETURN o f) x) *)


subsection ‹Generic DFS Algorithm›
record ('v,'s) gen_dfs_struct = 
  gds_init :: "'s nres"
  gds_is_break :: "'s  bool"
  gds_is_empty_stack :: "'s  bool"
  gds_new_root :: "'v  's  's nres"
  gds_get_pending :: "'s  ('v × 'v option × 's) nres"
  gds_finish :: "'v  's  's nres"
  gds_is_discovered :: "'v  's  bool"
  gds_is_finished :: "'v  's  bool"
  gds_back_edge :: "'v  'v  's  's nres"
  gds_cross_edge :: "'v  'v  's  's nres"
  gds_discover :: "'v  'v  's  's nres"


locale gen_dfs_defs =
  fixes gds :: "('v,'s) gen_dfs_struct"
  fixes V0 :: "'v set"
begin

  definition "gen_step s  
    if gds_is_empty_stack gds s then do {
      v0  SPEC (λv0. v0V0  ¬gds_is_discovered gds v0 s);
      gds_new_root gds v0 s
    } else  do {
        (u,Vs,s)  gds_get_pending gds s;
        case Vs of 
          None  gds_finish gds u s 
        | Some v  do {
          if gds_is_discovered gds v s then (
            if gds_is_finished gds v s then
              gds_cross_edge gds u v s
            else
              gds_back_edge gds u v s
          ) else 
            gds_discover gds u v s
        }
      }"

  definition "gen_cond  s 
     (V0  {v. gds_is_discovered gds v s}  ¬gds_is_empty_stack gds s)
       ¬gds_is_break gds s"

  definition "gen_dfs 
     gds_init gds  WHILE gen_cond gen_step"

  definition "gen_dfsT 
     gds_init gds  WHILET gen_cond gen_step"

  abbreviation "gen_discovered s  {v . gds_is_discovered gds v s}"


  abbreviation "gen_rwof  rwof (gds_init gds) gen_cond gen_step"

  definition "pre_new_root v0 s  
    gen_rwof s  gds_is_empty_stack gds s  ¬gds_is_break gds s 
     v0V0 - gen_discovered s"

  definition "pre_get_pending s 
    gen_rwof s  ¬gds_is_empty_stack gds s  ¬gds_is_break gds s"

  definition "post_get_pending u Vs s0 s  pre_get_pending s0 
     inres (gds_get_pending gds s0) (u,Vs,s)"

  definition "pre_finish u s0 s  post_get_pending u None s0 s"  
  definition "pre_cross_edge u v s0 s  
    post_get_pending u (Some v) s0 s  gds_is_discovered gds v s 
     gds_is_finished gds v s"
  definition "pre_back_edge u v s0 s  
    post_get_pending u (Some v) s0 s  gds_is_discovered gds v s 
       ¬gds_is_finished gds v s"
  definition "pre_discover u v s0 s  
    post_get_pending u (Some v) s0 s  ¬gds_is_discovered gds v s"

  lemmas pre_defs = pre_new_root_def pre_get_pending_def post_get_pending_def
    pre_finish_def pre_cross_edge_def pre_back_edge_def pre_discover_def

  definition "gen_step_assert s  
    if gds_is_empty_stack gds s then do {
      v0  SPEC (λv0. v0V0  ¬gds_is_discovered gds v0 s);
      ASSERT (pre_new_root v0 s);
      gds_new_root gds v0 s
    } else do {
        ASSERT (pre_get_pending s);
        let s0=GHOST s;
        (u,Vs,s)  gds_get_pending gds s;
        case Vs of 
          None  do {ASSERT (pre_finish u s0 s); gds_finish gds u s}
        | Some v  do {
          if gds_is_discovered gds v s then do {
            if gds_is_finished gds v s then do {
              ASSERT (pre_cross_edge u v s0 s);
              gds_cross_edge gds u v s
            } else do {
              ASSERT (pre_back_edge u v s0 s);
              gds_back_edge gds u v s
            }
          } else do {
            ASSERT (pre_discover u v s0 s);
            gds_discover gds u v s
          }
        }
      }"

  definition "gen_dfs_assert 
     gds_init gds  WHILE gen_cond gen_step_assert"

  definition "gen_dfsT_assert 
     gds_init gds  WHILET gen_cond gen_step_assert"

  abbreviation "gen_rwof_assert  rwof (gds_init gds) gen_cond gen_step_assert"

  lemma gen_step_eq_assert: "gen_cond s; gen_rwof s
        gen_step s = gen_step_assert s"
    apply (rule antisym)
    subgoal  
      apply (unfold gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      apply refine_rcg  
      apply refine_dref_type
      by simp_all  
    
    subgoal    
      apply (simp (no_asm) only: gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      apply (refine_rcg bind_refine')
      apply refine_dref_type
      by (auto simp: pre_defs gen_cond_def) 
    done
        
  lemma gen_dfs_eq_assert: "gen_dfs = gen_dfs_assert"
    unfolding gen_dfs_def gen_dfs_assert_def
    apply (rule antisym)
      
    subgoal  
      apply (unfold gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      by (refine_rcg, refine_dref_type, simp_all) []

    subgoal    
      apply (subst (2) WHILE_eq_I_rwof)
      apply (rule refine_IdD)
      apply (refine_rcg, simp_all)

      apply (simp (no_asm) only: gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      apply (refine_rcg bind_refine')
      apply refine_dref_type  
      by (auto simp: pre_defs gen_cond_def)
    done

  lemma gen_dfsT_eq_assert: "gen_dfsT = gen_dfsT_assert"
    unfolding gen_dfsT_def gen_dfsT_assert_def
    apply (rule antisym)
    subgoal  
      apply (unfold gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      by (refine_rcg, refine_dref_type, simp_all) []

    subgoal  
      apply (subst (2) WHILET_eq_I_rwof)
      apply (rule refine_IdD)
      apply (refine_rcg, simp_all)
  
      apply (simp (no_asm) only: gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule refine_IdD)
      apply (refine_rcg bind_refine', refine_dref_type)
      by (auto simp: pre_defs gen_cond_def)
    done


  lemma gen_rwof_eq_assert:
    assumes NF: "nofail gen_dfs"
    shows "gen_rwof = gen_rwof_assert"
    apply (rule ext)
    apply (rule iffI)

    subgoal  
      apply (rule rwof_step_refine)
      apply (fold gen_dfs_assert_def gen_dfs_eq_assert, rule NF)
      apply assumption

      apply (simp (no_asm) only: gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule leofI)
      apply (rule refine_IdD)
      by (refine_rcg bind_refine', refine_dref_type,
              auto simp: pre_defs gen_cond_def) []

    subgoal  
      apply (rule rwof_step_refine)
      apply (fold gen_dfs_def, rule NF)
      apply assumption
  
      apply (simp (no_asm) only: gen_step_def[abs_def] gen_step_assert_def[abs_def]) []
      apply (unfold GHOST_elim_Let) []
      apply (rule leofI)
      apply (rule refine_IdD)
      by (refine_rcg bind_refine', refine_dref_type,
              auto simp: pre_defs gen_cond_def) []
    done

  lemma gen_dfs_le_gen_dfsT: "gen_dfs  gen_dfsT" 
    unfolding gen_dfs_def gen_dfsT_def
    apply (rule bind_mono)
    apply simp
    unfolding WHILET_def WHILE_def
    apply (rule WHILEI_le_WHILEIT)
    done


end

locale gen_dfs = gen_dfs_defs gds V0 
  for gds :: "('v,'s) gen_dfs_struct"
  and V0 :: "'v set"

(* Formalize the structure of a parameterized DFS *)

(* Define the operations on the basic state *)
record ('v,'s,'es) gen_basic_dfs_struct = 
  gbs_init :: "'es  's nres"
  gbs_is_empty_stack :: "'s  bool"
  gbs_new_root :: "'v  's  's nres"
  gbs_get_pending :: "'s  ('v × 'v option × 's) nres"
  gbs_finish :: "'v  's  's nres"
  gbs_is_discovered :: "'v  's  bool"
  gbs_is_finished :: "'v  's  bool"
  gbs_back_edge :: "'v  'v  's  's nres"
  gbs_cross_edge :: "'v  'v  's  's nres"
  gbs_discover :: "'v  'v  's  's nres"



locale gen_param_dfs_defs =
  fixes gbs :: "('v,'s,'es) gen_basic_dfs_struct"
  fixes param :: "('v,'s,'es) gen_parameterization"
  fixes upd_ext :: "('es'es)  's  's"
  fixes V0 :: "'v set"
begin

  definition "do_action bf ef s  do {
    s  bf s;
    e  ef s;
    RETURN (upd_ext (λ_. e) s)
  }"

  definition "do_init  do {
    e  on_init param;
    gbs_init gbs e
  }"

  definition "do_new_root v0 
     do_action (gbs_new_root gbs v0) (on_new_root param v0)"  

  definition "do_finish u 
     do_action (gbs_finish gbs u) (on_finish param u)"

  definition "do_back_edge u v
     do_action (gbs_back_edge gbs u v) (on_back_edge param u v)"

  definition "do_cross_edge u v
     do_action (gbs_cross_edge gbs u v) (on_cross_edge param u v)"
  
  definition "do_discover u v
     do_action (gbs_discover gbs u v) (on_discover param u v)"

  lemmas do_action_defs[DFS_code_unfold] = 
    do_action_def do_init_def do_new_root_def
    do_finish_def do_back_edge_def do_cross_edge_def do_discover_def

  definition "gds  
    gds_init = do_init,
    gds_is_break = is_break param,
    gds_is_empty_stack = gbs_is_empty_stack gbs,
    gds_new_root = do_new_root,
    gds_get_pending = gbs_get_pending gbs,
    gds_finish = do_finish,
    gds_is_discovered = gbs_is_discovered gbs,
    gds_is_finished = gbs_is_finished gbs,
    gds_back_edge = do_back_edge,
    gds_cross_edge = do_cross_edge,
    gds_discover = do_discover
  "

  lemmas gds_simps[simp,DFS_code_unfold] 
    = gen_dfs_struct.simps[mk_record_simp, OF gds_def]

  sublocale gen_dfs_defs gds V0 .
end

locale gen_param_dfs = gen_param_dfs_defs gbs param upd_ext V0
  for gbs :: "('v,'s,'es) gen_basic_dfs_struct"
  and param :: "('v,'s,'es) gen_parameterization"
  and upd_ext :: "('es'es)  's  's"
  and V0 :: "'v set"

context param_DFS_defs begin

  definition "gbs  
    gbs_init = RETURN o empty_state,
    gbs_is_empty_stack = is_empty_stack ,
    gbs_new_root = RETURN oo new_root ,
    gbs_get_pending = get_pending ,
    gbs_finish = RETURN oo finish ,
    gbs_is_discovered = is_discovered ,
    gbs_is_finished = is_finished ,
    gbs_back_edge = RETURN ooo back_edge ,
    gbs_cross_edge = RETURN ooo cross_edge ,
    gbs_discover = RETURN ooo discover
  "

  lemmas gbs_simps[simp] = gen_basic_dfs_struct.simps[mk_record_simp, OF gbs_def]

  sublocale gen_dfs: gen_param_dfs_defs gbs param state.more_update V0 .

  lemma gen_cond_simp[simp]: "gen_dfs.gen_cond = cond"
    apply (intro ext)
    unfolding cond_def gen_dfs.gen_cond_def
    by simp

  lemma gen_step_simp[simp]: "gen_dfs.gen_step = step"  
    apply (intro ext)
    unfolding gen_dfs.gen_step_def[abs_def] 
    apply (simp 
      cong: if_cong option.case_cong 
      add: gen_dfs.do_action_defs[abs_def])

    unfolding step_def[abs_def] do_defs get_new_root_def pred_defs
    apply (simp 
      cong: if_cong option.case_cong)
    done

  lemma gen_init_simp[simp]: "gen_dfs.do_init = init"
    unfolding init_def
    apply (simp add: gen_dfs.do_action_defs[abs_def])
    done

  lemma gen_dfs_simp[simp]: "gen_dfs.gen_dfs = it_dfs"
    unfolding it_dfs_def gen_dfs.gen_dfs_def 
    apply (simp)
    done

  lemma gen_dfsT_simp[simp]: "gen_dfs.gen_dfsT = it_dfsT"
    unfolding it_dfsT_def gen_dfs.gen_dfsT_def 
    apply (simp)
    done

end

context param_DFS begin
  sublocale gen_dfs: gen_param_dfs gbs param state.more_update V0 .
end


subsection ‹Refinement Between DFS Implementations›
(* This locale expresses refinement between two general DFS implementations *)

locale gen_dfs_refine_defs =
  c: gen_dfs_defs gdsi V0i + a: gen_dfs_defs gds V0 
  for gdsi V0i gds V0

locale gen_dfs_refine =
  c: gen_dfs gdsi V0i + a: gen_dfs gds V0 + gen_dfs_refine_defs gdsi V0i gds V0
  for gdsi V0i gds V0 +
  fixes V S
  assumes BIJV[relator_props]: "bijective V"
  assumes V0_param[param]: "(V0i,V0)Vset_rel"
  assumes is_discovered_param[param]: (* TODO: Add preconditions for predicate refinement assumption *)
    "(gds_is_discovered gdsi,gds_is_discovered gds)VSbool_rel"
  assumes is_finished_param[param]: 
    "(gds_is_finished gdsi,gds_is_finished gds)VSbool_rel"
  assumes is_empty_stack_param[param]:
    "(gds_is_empty_stack gdsi,gds_is_empty_stack gds)Sbool_rel"
  assumes is_break_param[param]:
    "(gds_is_break gdsi,gds_is_break gds)Sbool_rel"
  assumes init_refine[refine]: 
    "gds_init gdsi   S (gds_init gds)"
  assumes new_root_refine[refine]: 
    "a.pre_new_root v0 s; (v0i,v0)V; (si,s)S 
       gds_new_root gdsi v0i si   S (gds_new_root gds v0 s)"
  assumes get_pending_refine[refine]:
    "a.pre_get_pending s; (si,s)S
       gds_get_pending gdsi si  (V ×r Voption_rel ×r S) (gds_get_pending gds s)"
  assumes finish_refine[refine]: 
    "a.pre_finish v s0 s; (vi,v)V; (si,s)S 
       gds_finish gdsi vi si   S (gds_finish gds v s)"
  assumes cross_edge_refine[refine]: 
    "a.pre_cross_edge u v s0 s; (ui,u)V; (vi,v)V; (si,s)S 
       gds_cross_edge gdsi ui vi si   S (gds_cross_edge gds u v s)"
  assumes back_edge_refine[refine]: 
    "a.pre_back_edge u v s0 s; (ui,u)V; (vi,v)V; (si,s)S 
       gds_back_edge gdsi ui vi si   S (gds_back_edge gds u v s)"
  assumes discover_refine[refine]: 
    "a.pre_discover u v s0 s; (ui,u)V; (vi,v)V; (si,s)S 
       gds_discover gdsi ui vi si   S (gds_discover gds u v s)"

begin
  term "gds_is_discovered gdsi"

  (*sublocale bij_rel_param!: bij_rel_param V using BIJV by unfold_locales*)

  lemma select_v0_refine[refine]:
    assumes s_param: "(si,s)S"
    shows "SPEC (λv0. v0  V0i  ¬ gds_is_discovered gdsi v0 si)
             V (SPEC (λv0. v0  V0  ¬ gds_is_discovered gds v0 s))"
    apply (rule RES_refine)
    apply (simp add: Bex_def[symmetric], elim conjE)
    apply (drule set_relD1[OF V0_param], elim bexE)
    apply (erule bexI[rotated])
    using is_discovered_param[param_fo, OF _ s_param]
    apply auto
    done

  lemma gen_rwof_refine: 
    assumes NF: "nofail (a.gen_dfs)"
    assumes RW: "c.gen_rwof s"
    obtains s' where "(s,s')S" and "a.gen_rwof s'"
  proof -
    from NF have NFa: "nofail (a.gen_dfs_assert)"
      unfolding a.gen_dfs_eq_assert .

    have "s'. (s, s')  S  a.gen_rwof_assert s'"
      apply (rule rwof_refine[OF RW NFa[unfolded a.gen_dfs_assert_def]])

      apply (rule leofI, rule init_refine)
    
      (* TODO: Proof duplication between this and gen_dfs_refine.
        Hope for better rwof/mgi-theory!
      *)
      unfolding c.gen_cond_def a.gen_cond_def
      apply (rule IdD)
      apply (simp only: subset_Collect_conv)
      apply parametricity 
    
      unfolding c.gen_step_def a.gen_step_assert_def GHOST_elim_Let
      apply (rule leofI)
      apply (refine_rcg IdD)
      apply simp_all
      apply ((rule IdD, parametricity) | (auto) [])+
      done
    thus ?thesis 
      unfolding a.gen_rwof_eq_assert[OF NF, symmetric]
      by (blast intro: that)
  qed

  lemma gen_step_refine[refine]: "(si,s)S  c.gen_step si  S (a.gen_step_assert s)"
    unfolding c.gen_step_def a.gen_step_assert_def GHOST_elim_Let
    apply (refine_rcg IdD)
    apply simp_all
    apply ((rule IdD, parametricity) | (auto) [])+
    done
    


  lemma gen_dfs_refine[refine]: "c.gen_dfs  S a.gen_dfs"  
    unfolding c.gen_dfs_def a.gen_dfs_eq_assert[unfolded a.gen_dfs_assert_def]
    apply refine_rcg
    unfolding c.gen_cond_def a.gen_cond_def
    apply (rule IdD)
    apply (simp only: subset_Collect_conv)
    apply parametricity 
    done

  lemma gen_dfsT_refine[refine]: "c.gen_dfsT  S a.gen_dfsT"  
    unfolding c.gen_dfsT_def a.gen_dfsT_eq_assert[unfolded a.gen_dfsT_assert_def]
    apply refine_rcg
    unfolding c.gen_cond_def a.gen_cond_def
    apply (rule IdD)
    apply (simp only: subset_Collect_conv)
    apply parametricity 
    done

end


(* Locale that states refinement of basic operations, without making 
  assumptions on parameterization *)
locale gbs_refinement =
  c: gen_param_dfs gbsi parami upd_exti V0i +
  a: gen_param_dfs gbs param upd_ext V0
  for gbsi parami upd_exti V0i gbs param upd_ext V0 +
  fixes V S ES
  assumes BIJV: "bijective V"
  assumes V0_param[param]: "(V0i,V0)Vset_rel"

  assumes is_discovered_param[param]: 
    "(gbs_is_discovered gbsi,gbs_is_discovered gbs)VSbool_rel"

  assumes is_finished_param[param]: 
    "(gbs_is_finished gbsi,gbs_is_finished gbs)VSbool_rel"

  assumes is_empty_stack_param[param]:
    "(gbs_is_empty_stack gbsi,gbs_is_empty_stack gbs)Sbool_rel"

  assumes is_break_param[param]:
    "(is_break parami,is_break param)Sbool_rel"

  assumes gbs_init_refine[refine]: "(ei, e)  ES  gbs_init gbsi ei   S (gbs_init gbs e)"

  assumes gbs_new_root_refine[refine]:
    "a.pre_new_root v0 s; (v0i, v0)  V; (si, s)  S
        gbs_new_root gbsi v0i si   S (gbs_new_root gbs v0 s)"

  assumes gbs_get_pending_refine[refine]:
    "a.pre_get_pending s; (si, s)  S
             gbs_get_pending gbsi si
                  (V ×r Voption_rel ×r S) (gbs_get_pending gbs s)"

  assumes gbs_finish_refine[refine]:
    "a.pre_finish v s0 s; (vi, v)  V; (si, s)  S
        gbs_finish gbsi vi si   S (gbs_finish gbs v s)"

  assumes gbs_cross_edge_refine[refine]:
    "a.pre_cross_edge u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S
       gbs_cross_edge gbsi ui vi si   S (gbs_cross_edge gbs u v s)"

  assumes gbs_back_edge_refine[refine]:
    "a.pre_back_edge u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S
       gbs_back_edge gbsi ui vi si   S (gbs_back_edge gbs u v s)"

  assumes gbs_discover_refine[refine]:
    "a.pre_discover u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S
       gbs_discover gbsi ui vi si   S (gbs_discover gbs u v s)"

(* Locale that states refinement of parameterization, without making
  assumptions on basic operations *)
locale param_refinement =
  c: gen_param_dfs gbsi parami upd_exti V0i +
  a: gen_param_dfs gbs param upd_ext V0
  for gbsi parami upd_exti V0i gbs param upd_ext V0 +
  fixes V S ES
  assumes upd_ext_param[param]: "(upd_exti, upd_ext)(ES  ES)  S  S"

  assumes on_init_refine[refine]: "on_init parami   ES (on_init param)"

  assumes is_break_param[param]: 
    "(is_break parami, is_break param)  S  bool_rel"

  assumes on_new_root_refine[refine]:
    "a.pre_new_root v0 s; (v0i, v0)  V; (si, s)  S;
        (si', s')  S; nf_inres (gbs_new_root gbs v0 s) s'
        on_new_root parami v0i si'   ES (on_new_root param v0 s')"

  assumes on_finish_refine[refine]:
    "a.pre_finish v s0 s; (vi, v)  V; (si, s)  S; (si', s')  S;
        nf_inres (gbs_finish gbs v s) s'
        on_finish parami vi si'   ES (on_finish param v s')"

  assumes on_cross_edge_refine[refine]:
    "a.pre_cross_edge u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S;
        (si', s')  S; nf_inres (gbs_cross_edge gbs u v s) s'
        on_cross_edge parami ui vi si'   ES (on_cross_edge param u v s')"

  assumes on_back_edge_refine[refine]:
    "a.pre_back_edge u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S;
        (si', s')  S; nf_inres (gbs_back_edge gbs u v s) s'
        on_back_edge parami ui vi si'   ES (on_back_edge param u v s')"

  assumes on_discover_refine[refine]:
    "a.pre_discover u v s0 s; (ui, u)  V; (vi, v)  V; (si, s)  S;
        (si', s')  S; nf_inres (gbs_discover gbs u v s) s'
        on_discover parami ui vi si'   ES (on_discover param u v s')"


locale gen_param_dfs_refine_defs =
  c: gen_param_dfs_defs gbsi parami upd_exti V0i +
  a: gen_param_dfs_defs gbs param upd_ext V0
  for gbsi parami upd_exti V0i gbs param upd_ext V0
begin
  sublocale gen_dfs_refine_defs c.gds V0i a.gds V0 .
end

locale gen_param_dfs_refine =
  gbs_refinement where V=V and S=S and ES=ES 
+ param_refinement where V=V and S=S and ES=ES
+ gen_param_dfs_refine_defs
  for V :: "('vi×'v) set" and S:: "('si×'s) set" and ES :: "('esi×'es) set"
begin

  sublocale gen_dfs_refine c.gds V0i a.gds V0 V S
    apply unfold_locales
    apply (simp_all add: BIJV V0_param a.do_action_defs c.do_action_defs)
    apply (parametricity+) [4]
    apply refine_rcg
    apply (refine_rcg bind_refine_abs', assumption+, parametricity) []
    apply refine_rcg
    apply (refine_rcg bind_refine_abs', assumption+, parametricity) []
    apply (refine_rcg bind_refine_abs', assumption+, parametricity) []
    apply (refine_rcg bind_refine_abs', assumption+, parametricity) []
    apply (refine_rcg bind_refine_abs', assumption+, parametricity) []
    done

end

end