header {* \isaheader{CFG well-formedness} *}
theory CFG_wf imports CFG begin
locale CFG_wf = CFG sourcenode targetnode kind valid_edge Entry 
    get_proc get_return_edges procs Main
  for sourcenode :: "'edge => 'node" and targetnode :: "'edge => 'node"
  and kind :: "'edge => ('var,'val,'ret,'pname) edge_kind" 
  and valid_edge :: "'edge => bool"
  and Entry :: "'node" ("'('_Entry'_')")  and get_proc :: "'node => 'pname"
  and get_return_edges :: "'edge => 'edge set"
  and procs :: "('pname × 'var list × 'var list) list" and Main :: "'pname" +
  fixes Def::"'node => 'var set"
  fixes Use::"'node => 'var set"
  fixes ParamDefs::"'node => 'var list"
  fixes ParamUses::"'node => 'var set list"
  assumes Entry_empty:"Def (_Entry_) = {} ∧ Use (_Entry_) = {}"
  and ParamUses_call_source_length:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs; (p,ins,outs) ∈ set procs|]
    ==> length(ParamUses (sourcenode a)) = length ins"
  and distinct_ParamDefs:"valid_edge a ==> distinct (ParamDefs (targetnode a))"
  and ParamDefs_return_target_length:
    "[|valid_edge a; kind a = Q'\<hookleftarrow>⇘p⇙f'; (p,ins,outs) ∈ set procs|]
    ==> length(ParamDefs (targetnode a)) = length outs"
  and ParamDefs_in_Def:
    "[|valid_node n; V ∈ set (ParamDefs n)|] ==> V ∈ Def n"
  and ins_in_Def:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs; (p,ins,outs) ∈ set procs; V ∈ set ins|]
    ==> V ∈ Def (targetnode a)"
  and call_source_Def_empty:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs|] ==> Def (sourcenode a) = {}"
  and ParamUses_in_Use:
    "[|valid_node n; V ∈ Union (set (ParamUses n))|] ==> V ∈ Use n"
  and outs_in_Use:
    "[|valid_edge a; kind a = Q\<hookleftarrow>⇘p⇙f; (p,ins,outs) ∈ set procs; V ∈ set outs|] 
    ==> V ∈ Use (sourcenode a)"
  and CFG_intra_edge_no_Def_equal:
    "[|valid_edge a; V ∉ Def (sourcenode a); intra_kind (kind a); pred (kind a) s|]
    ==> state_val (transfer (kind a) s) V = state_val s V"
  and CFG_intra_edge_transfer_uses_only_Use:
    "[|valid_edge a; ∀V ∈ Use (sourcenode a). state_val s V = state_val s' V;
      intra_kind (kind a); pred (kind a) s; pred (kind a) s'|]
    ==> ∀V ∈ Def (sourcenode a). state_val (transfer (kind a) s) V =
                                state_val (transfer (kind a) s') V"
  and CFG_edge_Uses_pred_equal:
    "[|valid_edge a; pred (kind a) s; snd (hd s) = snd (hd s');
      ∀V ∈ Use (sourcenode a). state_val s V = state_val s' V; length s = length s'|]
    ==> pred (kind a) s'"
  and CFG_call_edge_length:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs; (p,ins,outs) ∈ set procs|]
    ==> length fs = length ins"
  and CFG_call_determ:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs; valid_edge a'; kind a' = Q':r'\<hookrightarrow>⇘p'⇙fs';
      sourcenode a = sourcenode a'; pred (kind a) s; pred (kind a') s|]
    ==> a = a'"
  and CFG_call_edge_params:
    "[|valid_edge a; kind a = Q:r\<hookrightarrow>⇘p⇙fs; i < length ins; 
      (p,ins,outs) ∈ set procs; pred (kind a) s; pred (kind a) s';
      ∀V ∈ (ParamUses (sourcenode a))!i. state_val s V = state_val s' V|]
    ==> (params fs (fst (hd s)))!i = (params fs (fst (hd s')))!i"  
  and CFG_return_edge_fun:
    "[|valid_edge a; kind a = Q'\<hookleftarrow>⇘p⇙f'; (p,ins,outs) ∈ set procs|]
     ==> f' vmap vmap' = vmap'(ParamDefs (targetnode a) [:=] map vmap outs)"
  and deterministic:"[|valid_edge a; valid_edge a'; sourcenode a = sourcenode a';
    targetnode a ≠ targetnode a'; intra_kind (kind a); intra_kind (kind a')|] 
    ==> ∃Q Q'. kind a = (Q)⇣\<surd> ∧ kind a' = (Q')⇣\<surd> ∧ 
             (∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))"
begin
lemma CFG_equal_Use_equal_call:
  assumes "valid_edge a" and "kind a = Q:r\<hookrightarrow>⇘p⇙fs" and "valid_edge a'"
  and "kind a' = Q':r'\<hookrightarrow>⇘p'⇙fs'" and "sourcenode a = sourcenode a'"
  and "pred (kind a) s" and "pred (kind a') s'" 
  and "snd (hd s) = snd (hd s')" and "length s = length s'"
  and "∀V ∈ Use (sourcenode a). state_val s V = state_val s' V"
  shows "a = a'"
proof -
  from `valid_edge a` `pred (kind a) s` `snd (hd s) = snd (hd s')`
    `∀V ∈ Use (sourcenode a). state_val s V = state_val s' V` `length s = length s'`
  have "pred (kind a) s'" by(rule CFG_edge_Uses_pred_equal)
  with `valid_edge a` `kind a = Q:r\<hookrightarrow>⇘p⇙fs` `valid_edge a'` `kind a' = Q':r'\<hookrightarrow>⇘p'⇙fs'`
    `sourcenode a = sourcenode a'` `pred (kind a') s'`
  show ?thesis by -(rule CFG_call_determ)
qed
lemma CFG_call_edge_param_in:
  assumes "valid_edge a" and "kind a = Q:r\<hookrightarrow>⇘p⇙fs" and "i < length ins"
  and "(p,ins,outs) ∈ set procs" and "pred (kind a) s" and "pred (kind a) s'"
  and "∀V ∈ (ParamUses (sourcenode a))!i. state_val s V = state_val s' V"
  shows "state_val (transfer (kind a) s) (ins!i) = 
         state_val (transfer (kind a) s') (ins!i)"
proof -
  from assms have params:"(params fs (fst (hd s)))!i = (params fs (fst (hd s')))!i"
    by(rule CFG_call_edge_params)
  from `valid_edge a` `kind a = Q:r\<hookrightarrow>⇘p⇙fs` `(p,ins,outs) ∈ set procs`
  have [simp]:"(THE ins. ∃outs. (p,ins,outs) ∈ set procs) = ins"
    by(rule formal_in_THE)
  from `pred (kind a) s` obtain cf cfs where [simp]:"s = cf#cfs" by(cases s) auto
  from `pred (kind a) s'` obtain cf' cfs' where [simp]:"s' = cf'#cfs'"
    by(cases s') auto
  from `kind a = Q:r\<hookrightarrow>⇘p⇙fs`
  have eqs:"fst (hd (transfer (kind a) s)) = (empty(ins [:=] params fs (fst cf)))"
    "fst (hd (transfer (kind a) s')) = (empty(ins [:=] params fs (fst cf')))"
    by simp_all
  from `valid_edge a` `kind a = Q:r\<hookrightarrow>⇘p⇙fs` `(p,ins,outs) ∈ set procs`
  have "length fs = length ins" by(rule CFG_call_edge_length)
  from `(p,ins,outs) ∈ set procs` have "distinct ins" by(rule distinct_formal_ins)
  with `i < length ins` `length fs = length ins`
  have "(empty(ins [:=] params fs (fst cf))) (ins!i) = (params fs (fst cf))!i"
    "(empty(ins [:=] params fs (fst cf'))) (ins!i) = (params fs (fst cf'))!i"
    by(fastforce intro:fun_upds_nth)+
  with eqs `kind a = Q:r\<hookrightarrow>⇘p⇙fs` params
  show ?thesis by simp
qed
lemma CFG_call_edge_no_param:
  assumes "valid_edge a" and "kind a = Q:r\<hookrightarrow>⇘p⇙fs" and "V ∉ set ins"
  and "(p,ins,outs) ∈ set procs" and "pred (kind a) s"
  shows "state_val (transfer (kind a) s) V = None"
proof -
  from `valid_edge a` `kind a = Q:r\<hookrightarrow>⇘p⇙fs` `(p,ins,outs) ∈ set procs`
  have [simp]:"(THE ins. ∃outs. (p,ins,outs) ∈ set procs) = ins"
    by(rule formal_in_THE)
  from `pred (kind a) s` obtain cf cfs where [simp]:"s = cf#cfs" by(cases s) auto
  from `V ∉ set ins` have "(empty(ins [:=] params fs (fst cf))) V = None"
    by(auto dest:fun_upds_notin)
  with `kind a = Q:r\<hookrightarrow>⇘p⇙fs` show ?thesis by simp
qed
lemma CFG_return_edge_param_out:
  assumes "valid_edge a" and "kind a = Q\<hookleftarrow>⇘p⇙f" and "i < length outs"
  and "(p,ins,outs) ∈ set procs" and "state_val s (outs!i) = state_val s' (outs!i)"
  and "s = cf#cfx#cfs" and "s' = cf'#cfx'#cfs'"
  shows "state_val (transfer (kind a) s) ((ParamDefs (targetnode a))!i) =
         state_val (transfer (kind a) s') ((ParamDefs (targetnode a))!i)"
proof -
  from `valid_edge a` `kind a = Q\<hookleftarrow>⇘p⇙f` `(p,ins,outs) ∈ set procs`
  have [simp]:"(THE outs. ∃ins. (p,ins,outs) ∈ set procs) = outs"
    by(rule formal_out_THE)
  from `valid_edge a` `kind a = Q\<hookleftarrow>⇘p⇙f` `(p,ins,outs) ∈ set procs` `s = cf#cfx#cfs`
  have transfer:"fst (hd (transfer (kind a) s)) = 
    (fst cfx)(ParamDefs (targetnode a) [:=] map (fst cf) outs)"
    by(fastforce intro:CFG_return_edge_fun)
  from `valid_edge a` `kind a = Q\<hookleftarrow>⇘p⇙f` `(p,ins,outs) ∈ set procs` `s' = cf'#cfx'#cfs'`
  have transfer':"fst (hd (transfer (kind a) s')) = 
    (fst cfx')(ParamDefs (targetnode a) [:=] map (fst cf') outs)"
    by(fastforce intro:CFG_return_edge_fun)
  from `state_val s (outs!i) = state_val s' (outs!i)` `i < length outs`
    `s = cf#cfx#cfs` `s' = cf'#cfx'#cfs'`
  have "(fst cf) (outs!i) = (fst cf') (outs!i)" by simp
  from `valid_edge a` have "distinct (ParamDefs (targetnode a))"
    by(fastforce intro:distinct_ParamDefs)
  from `valid_edge a` `kind a = Q\<hookleftarrow>⇘p⇙f` `(p,ins,outs) ∈ set procs`
  have "length(ParamDefs (targetnode a)) = length outs"
    by(fastforce intro:ParamDefs_return_target_length)
  with `i < length outs` `distinct (ParamDefs (targetnode a))`
  have "(fst cfx)(ParamDefs (targetnode a) [:=] map (fst cf) outs)
    ((ParamDefs (targetnode a))!i) = (map (fst cf) outs)!i" 
    and "(fst cfx')(ParamDefs (targetnode a) [:=] map (fst cf') outs)
             ((ParamDefs (targetnode a))!i) = (map (fst cf') outs)!i"
    by(fastforce intro:fun_upds_nth)+
  with transfer transfer' `(fst cf) (outs!i) = (fst cf') (outs!i)` `i < length outs`
  show ?thesis by simp
qed
lemma CFG_slp_no_Def_equal:
  assumes "n -as->⇘sl⇙* n'" and "valid_edge a" and "a' ∈ get_return_edges a"
  and "V ∉ set (ParamDefs (targetnode a'))" and "preds (kinds (a#as@[a'])) s"
  shows "state_val (transfers (kinds (a#as@[a'])) s) V = state_val s V"
proof -
  from `valid_edge a` `a' ∈ get_return_edges a` 
  obtain Q r p fs where "kind a = Q:r\<hookrightarrow>⇘p⇙fs"
    by(fastforce dest!:only_call_get_return_edges)
  with `valid_edge a` `a' ∈ get_return_edges a` obtain Q' f' where "kind a' = Q'\<hookleftarrow>⇘p⇙f'"
    by(fastforce dest!:call_return_edges)
  from `valid_edge a` `a' ∈ get_return_edges a` have "valid_edge a'"
    by(rule get_return_edges_valid)
  from `preds (kinds (a#as@[a'])) s` obtain cf cfs where [simp]:"s = cf#cfs"
    by(cases s,auto simp:kinds_def)
  from `valid_edge a` `kind a = Q:r\<hookrightarrow>⇘p⇙fs` obtain ins outs 
    where "(p,ins,outs) ∈ set procs" by(fastforce dest!:callee_in_procs)
  from `kind a = Q:r\<hookrightarrow>⇘p⇙fs` obtain cfx where "transfer (kind a) s = cfx#cf#cfs"
    by simp
  moreover
  from `n -as->⇘sl⇙* n'` obtain cfx' 
    where "transfers (kinds as) (cfx#cf#cfs) = cfx'#cf#cfs"
    by(fastforce elim:slp_callstack_length_equal)
  moreover
  from `kind a' = Q'\<hookleftarrow>⇘p⇙f'` `valid_edge a'` `(p,ins,outs) ∈ set procs`
  have "fst (hd (transfer (kind a') (cfx'#cf#cfs))) = 
    (fst cf)(ParamDefs (targetnode a') [:=] map (fst cfx') outs)"
    by(simp,simp only:formal_out_THE,fastforce intro:CFG_return_edge_fun)
  ultimately have "fst (hd (transfers (kinds (a#as@[a'])) s)) = 
    (fst cf)(ParamDefs (targetnode a') [:=] map (fst cfx') outs)"
    by(simp add:kinds_def transfers_split)
  with `V ∉ set (ParamDefs (targetnode a'))` show ?thesis
    by(simp add:fun_upds_notin)
qed
lemma [dest!]: "V ∈ Use (_Entry_) ==> False"
by(simp add:Entry_empty)
lemma [dest!]: "V ∈ Def (_Entry_) ==> False"
by(simp add:Entry_empty)
lemma CFG_intra_path_no_Def_equal:
  assumes "n -as->⇣ι* n'" and "∀n ∈ set (sourcenodes as). V ∉ Def n"
  and "preds (kinds as) s"
  shows "state_val (transfers (kinds as) s) V = state_val s V"
proof -
  from `n -as->⇣ι* n'` have "n -as->* n'" and "∀a ∈ set as. intra_kind (kind a)"
    by(simp_all add:intra_path_def)
  from this `∀n ∈ set (sourcenodes as). V ∉ Def n` `preds (kinds as) s`
  have "state_val (transfers (kinds as) s) V = state_val s V"
  proof(induct arbitrary:s rule:path.induct)
    case (empty_path n)
    thus ?case by(simp add:sourcenodes_def kinds_def)
  next
    case (Cons_path n'' as n' a n)
    note IH = `!!s. [|∀a∈set as. intra_kind (kind a); 
                    ∀n∈set (sourcenodes as). V ∉ Def n; preds (kinds as) s|] 
      ==> state_val (transfers (kinds as) s) V = state_val s V`
    from `preds (kinds (a#as)) s` have "pred (kind a) s"
      and "preds (kinds as) (transfer (kind a) s)" by(simp_all add:kinds_def)
    from `∀n∈set (sourcenodes (a#as)). V ∉ Def n`
    have noDef:"V ∉ Def (sourcenode a)" 
      and all:"∀n∈set (sourcenodes as). V ∉ Def n"
      by(auto simp:sourcenodes_def)
    from `∀a∈set (a#as). intra_kind (kind a)`
    have "intra_kind (kind a)" and all':"∀a∈set as. intra_kind (kind a)"
      by auto
    from `valid_edge a` noDef `intra_kind (kind a)` `pred (kind a) s`
    have "state_val (transfer (kind a) s) V = state_val s V"
     by -(rule CFG_intra_edge_no_Def_equal)
    with IH[OF all' all `preds (kinds as) (transfer (kind a) s)`] show ?case
      by(simp add:kinds_def)
  qed
  thus ?thesis by blast
qed
lemma slpa_preds:
  "[|same_level_path_aux cs as; s = cfsx@cf#cfs; s' = cfsx@cf#cfs'; 
    length cfs = length cfs'; ∀a ∈ set as. valid_edge a; length cs = length cfsx; 
    preds (kinds as) s|]
  ==> preds (kinds as) s'"
proof(induct arbitrary:s s' cf cfsx rule:slpa_induct)
  case (slpa_empty cs) thus ?case by(simp add:kinds_def)
next
  case (slpa_intra cs a as)
  note IH = `!!s s' cf cfsx. [|s = cfsx@cf#cfs; s' = cfsx@cf#cfs';
    length cfs = length cfs'; ∀a ∈ set as. valid_edge a; length cs = length cfsx; 
    preds (kinds as) s|] ==> preds (kinds as) s'`
  from `∀a∈set (a#as). valid_edge a` have "valid_edge a"
    and "∀a ∈ set as. valid_edge a" by simp_all
  from `preds (kinds (a#as)) s` have "pred (kind a) s"
    and "preds (kinds as) (transfer (kind a) s)" by(simp_all add:kinds_def)
  show ?case
  proof(cases cfsx)
    case Nil
    with `length cs = length cfsx` have "length cs = length []" by simp
    from Nil `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'` `intra_kind (kind a)` 
    obtain cfx where "transfer (kind a) s = []@cfx#cfs"
      and "transfer (kind a) s' = []@cfx#cfs'"
      by(cases "kind a",auto simp:kinds_def intra_kind_def)
    from IH[OF this `length cfs = length cfs'` `∀a ∈ set as. valid_edge a`
      `length cs = length []` `preds (kinds as) (transfer (kind a) s)`]
    have "preds (kinds as) (transfer (kind a) s')" .
    moreover
    from Nil `valid_edge a` `pred (kind a) s` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
      `length cfs = length cfs'`
    have "pred (kind a) s'" by(fastforce intro:CFG_edge_Uses_pred_equal)
    ultimately show ?thesis by(simp add:kinds_def)
  next
    case (Cons x xs)
    with `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'` `intra_kind (kind a)`
    obtain cfx where "transfer (kind a) s = (cfx#xs)@cf#cfs"
      and "transfer (kind a) s' = (cfx#xs)@cf#cfs'"
      by(cases "kind a",auto simp:kinds_def intra_kind_def)
    from IH[OF this `length cfs = length cfs'` `∀a ∈ set as. valid_edge a` _ 
      `preds (kinds as) (transfer (kind a) s)`] `length cs = length cfsx` Cons
    have "preds (kinds as) (transfer (kind a) s')" by simp
    moreover
    from Cons `valid_edge a` `pred (kind a) s` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
      `length cfs = length cfs'` 
    have "pred (kind a) s'" by(fastforce intro:CFG_edge_Uses_pred_equal)
    ultimately show ?thesis by(simp add:kinds_def)
  qed
next
  case (slpa_Call cs a as Q r p fs)
  note IH = `!!s s' cf cfsx. [|s = cfsx@cf#cfs; s' = cfsx@cf#cfs';
    length cfs = length cfs'; ∀a ∈ set as. valid_edge a; length (a#cs) = length cfsx;
    preds (kinds as) s|] ==> preds (kinds as) s'`
  from `∀a∈set (a#as). valid_edge a` have "valid_edge a"
    and "∀a ∈ set as. valid_edge a" by simp_all
  from `preds (kinds (a#as)) s` have "pred (kind a) s"
    and "preds (kinds as) (transfer (kind a) s)" by(simp_all add:kinds_def)
  from `kind a = Q:r\<hookrightarrow>⇘p⇙fs` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'` obtain cfx
    where "transfer (kind a) s = (cfx#cfsx)@cf#cfs"
    and "transfer (kind a) s' = (cfx#cfsx)@cf#cfs'" by(cases cfsx) auto
  from IH[OF this `length cfs = length cfs'` `∀a ∈ set as. valid_edge a` _ 
    `preds (kinds as) (transfer (kind a) s)`] `length cs = length cfsx`
  have "preds (kinds as) (transfer (kind a) s')" by simp
  moreover
  from `valid_edge a` `pred (kind a) s` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
    `length cfs = length cfs'` have "pred (kind a) s'" 
    by(cases cfsx)(auto intro:CFG_edge_Uses_pred_equal)
  ultimately show ?case by(simp add:kinds_def)
next
  case (slpa_Return cs a as Q p f c' cs')
  note IH = `!!s s' cf cfsx. [|s = cfsx@cf#cfs; s' = cfsx@cf#cfs';
    length cfs = length cfs'; ∀a ∈ set as. valid_edge a; length cs' = length cfsx; 
    preds (kinds as) s|] ==> preds (kinds as) s'`
  from `∀a∈set (a#as). valid_edge a` have "valid_edge a"
    and "∀a ∈ set as. valid_edge a" by simp_all
  from `preds (kinds (a#as)) s` have "pred (kind a) s"
    and "preds (kinds as) (transfer (kind a) s)" by(simp_all add:kinds_def)
  show ?case
  proof(cases cs')
    case Nil
    with `cs = c'#cs'` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
      `length cs = length cfsx` 
    obtain cf' where "s = cf'#cf#cfs" and "s' = cf'#cf#cfs'" by(cases cfsx) auto
    with `kind a = Q\<hookleftarrow>⇘p⇙f` obtain cf'' where "transfer (kind a) s = []@cf''#cfs"
      and "transfer (kind a) s' = []@cf''#cfs'" by auto
    from IH[OF this `length cfs = length cfs'` `∀a ∈ set as. valid_edge a` _ 
      `preds (kinds as) (transfer (kind a) s)`] Nil
    have "preds (kinds as) (transfer (kind a) s')" by simp
    moreover
    from `valid_edge a` `pred (kind a) s` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
      `length cfs = length cfs'`  have "pred (kind a) s'" 
      by(cases cfsx)(auto intro:CFG_edge_Uses_pred_equal)
    ultimately show ?thesis by(simp add:kinds_def)
  next
    case (Cons cx csx)
    with `cs = c'#cs'` `length cs = length cfsx` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
    obtain x x' xs where "s = (x#x'#xs)@cf#cfs" and "s' = (x#x'#xs)@cf#cfs'"
      and "length xs = length csx"
      by(cases cfsx,auto,case_tac list,fastforce+)
    with `kind a = Q\<hookleftarrow>⇘p⇙f` obtain cf' where "transfer (kind a) s = (cf'#xs)@cf#cfs"
      and "transfer (kind a) s' = (cf'#xs)@cf#cfs'"
      by fastforce
    from IH[OF this `length cfs = length cfs'` `∀a ∈ set as. valid_edge a` _ 
      `preds (kinds as) (transfer (kind a) s)`] Cons `length xs = length csx`
    have "preds (kinds as) (transfer (kind a) s')" by simp
    moreover
    from `valid_edge a` `pred (kind a) s` `s = cfsx@cf#cfs` `s' = cfsx@cf#cfs'`
      `length cfs = length cfs'`  have "pred (kind a) s'" 
      by(cases cfsx)(auto intro:CFG_edge_Uses_pred_equal)
    ultimately show ?thesis by(simp add:kinds_def)
  qed
qed
lemma slp_preds:
  assumes "n -as->⇘sl⇙* n'" and "preds (kinds as) (cf#cfs)" 
  and "length cfs = length cfs'"
  shows "preds (kinds as) (cf#cfs')"
proof -
  from `n -as->⇘sl⇙* n'` have "n -as->* n'" and "same_level_path_aux [] as"
    by(simp_all add:slp_def same_level_path_def)
  from `n -as->* n'` have "∀a ∈ set as. valid_edge a" by(rule path_valid_edges)
  with `same_level_path_aux [] as` `preds (kinds as) (cf#cfs)` 
    `length cfs = length cfs'`
  show ?thesis by(fastforce elim!:slpa_preds)
qed
end
end