Theory ValidPaths

section ‹Lemmas concerning paths to instantiate locale Postdomination›

theory ValidPaths imports WellFormed "../StaticInter/Postdomination" begin

subsection ‹Intraprocedural paths from method entry and to method exit›


abbreviation path :: "wf_prog  node  edge list  node  bool" ("_  _ -_→* _")
  where "wfp. wfp  n -as→* n'  CFG.path sourcenode targetnode (valid_edge wfp) n as n'"

definition label_incrs :: "edge list  nat  edge list" ("_ ⊕s _" 60)
  where "as ⊕s i  map (λ((p,n),et,(p',n')). ((p,n  i),et,(p',n'  i))) as"


declare One_nat_def [simp del]



subsubsection ‹From prog› to prog;;c2


lemma Proc_CFG_edge_SeqFirst_nodes_Label:
  "prog  Label l -etp Label l'  prog;;c2  Label l -etp Label l'"
proof(induct prog "Label l" et "Label l'" rule:Proc_CFG.induct)
  case (Proc_CFG_SeqSecond c2' n et n' c1)
  hence "(c1;; c2');; c2  n  #:c1 -etp n'  #:c1"
    by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_SeqSecond)
  with n  #:c1 = Label l n'  #:c1 = Label l' show ?case by fastforce
next
  case (Proc_CFG_CondThen c1 n et n' b c2')
  hence "if (b) c1 else c2';; c2  n  1 -etp n'  1"
    by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_CondThen)
  with n  1 = Label l n'  1 = Label l' show ?case by fastforce
next
  case (Proc_CFG_CondElse c1 n et n' b c2')
  hence "if (b) c2' else c1 ;; c2  n  #:c2' + 1 -etp n'  (#:c2' + 1)"   
    by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_CondElse)
  with n  #:c2' + 1 = Label l n'  #:c2' + 1 = Label l' show ?case by fastforce
next
  case (Proc_CFG_WhileBody c' n et n' b)
  hence "while (b) c';; c2  n  2 -etp n'  2"
    by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_WhileBody)
  with n  2 = Label l n'  2 = Label l' show ?case by fastforce
next
  case (Proc_CFG_WhileBodyExit c' n et b)
  hence "while (b) c';; c2  n  2 -etp Label 0"
    by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_WhileBodyExit)
  with n  2 = Label l 0 = l' show ?case by fastforce
qed (auto intro:Proc_CFG.intros)


lemma Proc_CFG_edge_SeqFirst_source_Label:
  assumes "prog  Label l -etp n'"
  obtains nx where "prog;;c2  Label l -etp nx"
proof(atomize_elim)
  from prog  Label l -etp n' obtain n where "prog  n -etp n'" and "Label l = n"
    by simp
  thus "nx. prog;;c2  Label l -etp nx"
  proof(induct prog n et n' rule:Proc_CFG.induct)
    case (Proc_CFG_SeqSecond c2' n et n' c1)
    show ?case
    proof(cases "n' = Exit")
      case True
      with c2'  n -etp n' n  Entry have "c1;; c2'  n  #:c1 -etp Exit  #:c1"
        by(fastforce intro:Proc_CFG.Proc_CFG_SeqSecond)
      moreover from n  Entry have "n  #:c1  Entry" by(cases n) auto
      ultimately
      have "c1;; c2';; c2  n  #:c1 -etp Label (#:c1;; c2')"
        by(fastforce intro:Proc_CFG_SeqConnect)
      with Label l = n  #:c1 show ?thesis by fastforce
    next
      case False
      with Proc_CFG_SeqSecond
      have "(c1;; c2');; c2  n  #:c1 -etp n'  #:c1"
        by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_SeqSecond)
      with Label l = n  #:c1 show ?thesis by fastforce
    qed
  next
    case (Proc_CFG_CondThen c1 n et n' b c2')
    show ?case
    proof(cases "n' = Exit")
      case True
      with c1  n -etp n' n  Entry
      have "if (b) c1 else c2'  n  1 -etp Exit  1"
        by(fastforce intro:Proc_CFG.Proc_CFG_CondThen)
      moreover from n  Entry have "n  1  Entry" by(cases n) auto
      ultimately
      have "if (b) c1 else c2';; c2  n  1 -etp Label (#:if (b) c1 else c2')"
        by(fastforce intro:Proc_CFG_SeqConnect)
      with Label l = n  1 show ?thesis by fastforce
    next
      case False
      hence "n'  1  Exit" by(cases n') auto
      with Proc_CFG_CondThen
      have  "if (b) c1 else c2';; c2  Label l -etp n'  1"
        by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_CondThen)
      with Label l = n  1 show ?thesis by fastforce
    qed
  next
    case (Proc_CFG_CondElse c1 n et n' b c2')
    show ?case
    proof(cases "n' = Exit")
      case True
      with c1  n -etp n' n  Entry
      have "if (b) c2' else c1  n  (#:c2' + 1) -etp Exit  (#:c2' + 1)"
        by(fastforce intro:Proc_CFG.Proc_CFG_CondElse)
      moreover from n  Entry have "n  (#:c2' + 1)  Entry" by(cases n) auto
      ultimately
      have "if (b) c2' else c1;; c2  n  (#:c2' + 1) -etp 
        Label (#:if (b) c2' else c1)"
        by(fastforce intro:Proc_CFG_SeqConnect)
      with Label l = n  (#:c2' + 1) show ?thesis by fastforce
    next
      case False
      hence "n'  (#:c2' + 1)  Exit" by(cases n') auto
      with Proc_CFG_CondElse
      have  "if (b) c2' else c1 ;; c2  Label l -etp n'  (#:c2' + 1)"
        by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_CondElse)
      with Label l = n  (#:c2' + 1) show ?thesis by fastforce
    qed
  qed (auto intro:Proc_CFG.intros)
qed


lemma Proc_CFG_edge_SeqFirst_target_Label:
  "prog  n -etp n'; Label l' = n'  prog;;c2  n -etp Label l'"
proof(induct prog n et n' rule:Proc_CFG.induct)
  case (Proc_CFG_SeqSecond c2' n et n' c1)
  from Label l' = n'  #:c1 have "n'  Exit" by(cases n') auto
  with Proc_CFG_SeqSecond
  show ?case by(fastforce intro:Proc_CFG_SeqFirst intro:Proc_CFG.Proc_CFG_SeqSecond)
next
  case (Proc_CFG_CondThen c1 n et n' b c2')
  from Label l' = n'  1 have "n'  Exit" by(cases n') auto
  with Proc_CFG_CondThen
  show ?case by(fastforce intro:Proc_CFG_SeqFirst Proc_CFG.Proc_CFG_CondThen)
qed (auto intro:Proc_CFG.intros)


lemma PCFG_edge_SeqFirst_source_Label:
  assumes "prog,procs  (p,Label l) -et (p',n')"
  obtains nx where "prog;;c2,procs  (p,Label l) -et (p',nx)"
proof(atomize_elim)
  from prog,procs  (p,Label l) -et (p',n')
  show "nx. prog;;c2,procs  (p,Label l) -et (p',nx)"
  proof(induct "(p,Label l)" et "(p',n')" rule:PCFG.induct)
    case (Main et)
    from prog  Label l -IEdge etp n'
    obtain nx' where "prog;;c2  Label l -IEdge etp nx'"
      by(auto elim:Proc_CFG_edge_SeqFirst_source_Label)
    with Main = p Main = p' show ?case 
      by(fastforce dest:PCFG.Main)
  next
    case (Proc ins outs c et ps)
    from containsCall procs prog ps p
    have "containsCall procs (prog;;c2) ps p" by simp
    with Proc show ?case by(fastforce dest:PCFG.Proc)
  next
    case (MainCall es rets nx ins outs c)
    from prog  Label l -CEdge (p', es, rets)p nx
    obtain lx where [simp]:"nx = Label lx" by(fastforce dest:Proc_CFG_Call_Labels)
    with prog  Label l -CEdge (p', es, rets)p nx
    have "prog;;c2  Label l -CEdge (p', es, rets)p Label lx"
      by(auto intro:Proc_CFG_edge_SeqFirst_nodes_Label)
    with MainCall show ?case by(fastforce dest:PCFG.MainCall)
  next
    case (ProcCall ins outs c es' rets' l' ins' outs' c' ps)
    from containsCall procs prog ps p 
    have "containsCall procs (prog;;c2) ps p" by simp
    with ProcCall show ?case by(fastforce intro:PCFG.ProcCall)
  next
    case (MainCallReturn px es rets)
    from prog  Label l -CEdge (px, es, rets)p n' Main = p
    obtain nx'' where "prog;;c2  Label l -CEdge (px, es, rets)p nx''"
      by(auto elim:Proc_CFG_edge_SeqFirst_source_Label)
    with MainCallReturn show ?case by(fastforce dest:PCFG.MainCallReturn)
  next
    case (ProcCallReturn ins outs c px' es' rets' ps)
    from containsCall procs prog ps p
    have "containsCall procs (prog;;c2) ps p" by simp
    with ProcCallReturn show ?case by(fastforce dest!:PCFG.ProcCallReturn)
  qed
qed


lemma PCFG_edge_SeqFirst_target_Label:
  "prog,procs  (p,n) -et (p',Label l') 
   prog;;c2,procs  (p,n) -et (p',Label l')"
proof(induct "(p,n)" et "(p',Label l')" rule:PCFG.induct)
  case Main
  thus ?case by(fastforce dest:Proc_CFG_edge_SeqFirst_target_Label intro:PCFG.Main)
next
  case (Proc ins outs c et ps)
  from containsCall procs prog ps p 
  have "containsCall procs (prog;;c2) ps p" by simp
  with Proc show ?case by(fastforce dest:PCFG.Proc)
next
  case MainReturn thus ?case
    by(fastforce dest:Proc_CFG_edge_SeqFirst_target_Label 
               intro!:PCFG.MainReturn[simplified])
next
  case (ProcReturn ins outs c lx es' rets' ins' outs' c' ps)
  from containsCall procs prog ps p' 
  have "containsCall procs (prog;;c2) ps p'" by simp
  with ProcReturn show ?case by(fastforce intro:PCFG.ProcReturn)
next
  case MainCallReturn thus ?case
  by(fastforce dest:Proc_CFG_edge_SeqFirst_target_Label intro:PCFG.MainCallReturn)
next
  case (ProcCallReturn ins outs c px' es' rets' ps)
  from containsCall procs prog ps p 
  have "containsCall procs (prog;;c2) ps p" by simp
  with ProcCallReturn show ?case by(fastforce dest!:PCFG.ProcCallReturn)
qed


lemma path_SeqFirst:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" and "Rep_wf_prog wfp' = (prog;;c2,procs)"
  shows "wfp  (p,n) -as→* (p,Label l); a  set as. intra_kind (kind a)
   wfp'  (p,n) -as→* (p,Label l)"
proof(induct "(p,n)" as "(p,Label l)" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (p, Label l) 
    Rep_wf_prog wfp = (prog, procs) Rep_wf_prog wfp' = (prog;; c2, procs)
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp') (p, Label l)"
    apply(auto simp:ProcCFG.valid_node_def valid_edge_def)
    apply(erule PCFG_edge_SeqFirst_source_Label,fastforce)
    by(drule PCFG_edge_SeqFirst_target_Label,fastforce)
  thus ?case by(fastforce intro:ProcCFG.empty_path)
next
  case (Cons_path n'' as a nx)
  note IH = n. n'' = (p, n); aset as. intra_kind (kind a)
     wfp'  (p, n) -as→* (p, Label l)
  note [simp] = Rep_wf_prog wfp = (prog,procs) Rep_wf_prog wfp' = (prog;;c2,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp a sourcenode a = (p, nx) targetnode a = n''
    intra_kind (kind a) wf 
  obtain nx' where "n'' = (p,nx')"
    by(auto elim:PCFG.cases simp:valid_edge_def intra_kind_def)
  from IH[OF this aset as. intra_kind (kind a)]
  have path:"wfp'  (p, nx') -as→* (p, Label l)" .
  have "valid_edge wfp' a"
  proof(cases nx')
    case (Label lx)
    with valid_edge wfp a sourcenode a = (p, nx) targetnode a = n''
      n'' = (p,nx') show ?thesis
      by(fastforce intro:PCFG_edge_SeqFirst_target_Label 
                   simp:intra_kind_def valid_edge_def)
  next
    case Entry
    with valid_edge wfp a targetnode a = n'' n'' = (p,nx')
      intra_kind (kind a) have False 
      by(auto elim:PCFG.cases simp:valid_edge_def intra_kind_def)
    thus ?thesis by simp
  next
    case Exit
    with path aset as. intra_kind (kind a) have False 
      by(induct "(p,nx')" as "(p,Label l)" rule:ProcCFG.path.induct)
    (auto elim!:PCFG.cases simp:valid_edge_def intra_kind_def)
    thus ?thesis by simp
  qed
  with sourcenode a = (p, nx) targetnode a = n'' n'' = (p,nx') path
  show ?case by(fastforce intro:ProcCFG.Cons_path)
qed


subsubsection ‹From prog› to c1;;prog›

lemma Proc_CFG_edge_SeqSecond_source_not_Entry:
  "prog  n -etp n'; n  Entry  c1;;prog  n  #:c1 -etp n'  #:c1"
by(induct rule:Proc_CFG.induct)(fastforce intro:Proc_CFG_SeqSecond Proc_CFG.intros)+


lemma PCFG_Main_edge_SeqSecond_source_not_Entry:
  "prog,procs  (Main,n) -et (p',n'); n  Entry; intra_kind et; well_formed procs
   c1;;prog,procs  (Main,n  #:c1) -et (p',n'  #:c1)"
proof(induct "(Main,n)" et "(p',n')" rule:PCFG.induct)
  case Main
  thus ?case
    by(fastforce dest:Proc_CFG_edge_SeqSecond_source_not_Entry intro:PCFG.Main)
next
  case (MainCallReturn p es rets)
  from prog  n -CEdge (p, es, rets)p n' n  Entry
  have "c1;;prog  n  #:c1 -CEdge (p, es, rets)p n'  #:c1"
    by(rule Proc_CFG_edge_SeqSecond_source_not_Entry)
  with MainCallReturn show ?case by(fastforce intro:PCFG.MainCallReturn)
qed (auto simp:intra_kind_def)


lemma valid_node_Main_SeqSecond:
  fixes wfp
  assumes "CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)"
  and "n  Entry" and "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (c1;;prog,procs)"
  shows "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n  #:c1)"
proof -
  note [simp] = Rep_wf_prog wfp = (prog,procs) Rep_wf_prog wfp' = (c1;;prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)
  obtain a where "prog,procs  sourcenode a -kind a targetnode a"
    and "(Main,n) = sourcenode a  (Main,n) = targetnode a"
    by(fastforce simp:ProcCFG.valid_node_def valid_edge_def)
  from this n  Entry wf show ?thesis
  proof(induct "sourcenode a" "kind a" "targetnode a" rule:PCFG.induct)
    case (Main nx nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -IEdge (kind a)p nx'
      have "c1;;prog  n  #:c1 -IEdge (kind a)p nx'  #:c1"
        by(fastforce intro:Proc_CFG_edge_SeqSecond_source_not_Entry)
      hence "c1;;prog,procs  (Main,n  #:c1) -kind a (Main,nx'  #:c1)"
        by(rule PCFG.Main)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      show ?thesis
      proof(cases "nx = Entry")
        case True
        with prog  nx -IEdge (kind a)p nx' 
        have "nx' = Exit  nx' = Label 0" by(fastforce dest:Proc_CFG_EntryD)
        thus ?thesis
        proof
          assume "nx' = Exit"
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis by simp
        next
          assume "nx' = Label 0"
          obtain l etx where "c1  Label l -IEdge etxp Exit" and "l  #:c1"
            by(erule Proc_CFG_Exit_edge)
          hence "c1;;prog  Label l -IEdge etxp Label #:c1"
            by(fastforce intro:Proc_CFG_SeqConnect)
          with nx' = Label 0 
          have "c1;;prog,procs  (Main,Label l) -etx (Main,nx'#:c1)"
            by(fastforce intro:PCFG.Main)
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis
            by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
        qed
      next
        case False
        with prog  nx -IEdge (kind a)p nx'
        have "c1;;prog  nx  #:c1 -IEdge (kind a)p nx'  #:c1"
          by(fastforce intro:Proc_CFG_edge_SeqSecond_source_not_Entry)
        hence "c1;;prog,procs  (Main,nx  #:c1) -kind a (Main,nx'  #:c1)"
          by(rule PCFG.Main)
        with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
        show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
      qed
    qed
  next
    case (Proc p ins outs c nx n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (Main, n) = sourcenode a  (Main, n) = targetnode a 
      (p, ins, outs, c)  set procs well_formed procs have False by fastforce
    thus ?case by simp
  next
    case (MainCall l p es rets n' ins outs c)
    from (p, ins, outs, c)  set procs wf (p, Entry) = targetnode a[THEN sym]
      (Main, Label l) = sourcenode a[THEN sym]
      (Main, n) = sourcenode a  (Main, n) = targetnode a
     have [simp]:"n = Label l" by fastforce
    from prog  Label l -CEdge (p, es, rets)p n'
    have "c1;;prog  Label l  #:c1 -CEdge (p, es, rets)p n'  #:c1"
      by -(rule Proc_CFG_edge_SeqSecond_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "c1;;prog,procs  (Main,Label (l + #:c1)) 
      -(λs. True):(Main,n'  #:c1)↪⇘pmap (λe cf. interpret e cf) es (p,Entry)"
      by(fastforce intro:PCFG.MainCall)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcCall p ins outs c l p' es' rets' l' ins' outs' c')
    from (p, Label l) = sourcenode a[THEN sym]
      (p', Entry) = targetnode a[THEN sym]  well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainReturn l p es rets l' ins outs c)
    from (p, ins, outs, c)  set procs wf (p, Exit) = sourcenode a[THEN sym]
      (Main, Label l') = targetnode a[THEN sym]
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l'" by fastforce
    from prog  Label l -CEdge (p, es, rets)p Label l'
    have "c1;;prog  Label l  #:c1 -CEdge (p, es, rets)p Label l'  #:c1"
      by -(rule Proc_CFG_edge_SeqSecond_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "c1;;prog,procs  (p,Exit) -(λcf. snd cf = (Main,Label l'  #:c1))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (Main,Label (l' + #:c1))"
      by(fastforce intro:PCFG.MainReturn)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcReturn p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p', Exit) = sourcenode a[THEN sym] 
      (p, Label l') = targetnode a[THEN sym] well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCallReturn nx p es rets nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -CEdge (p, es, rets)p nx'
      have "c1;;prog  n  #:c1 -CEdge (p, es, rets)p nx'  #:c1"
        by(fastforce intro:Proc_CFG_edge_SeqSecond_source_not_Entry)
      hence "c1;;prog,procs  (Main,n  #:c1) -(λs. False) (Main,nx'  #:c1)"
        by -(rule PCFG.MainCallReturn)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      from prog  nx -CEdge (p, es, rets)p nx'
      have "nx  Entry" by(fastforce dest:Proc_CFG_Call_Labels)
      with prog  nx -CEdge (p, es, rets)p nx'
      have "c1;;prog  nx  #:c1 -CEdge (p, es, rets)p nx'  #:c1"
        by(fastforce intro:Proc_CFG_edge_SeqSecond_source_not_Entry)
      hence "c1;;prog,procs  (Main,nx  #:c1) -(λs. False) (Main,nx'  #:c1)"
        by -(rule PCFG.MainCallReturn)
      with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym] 
      show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    qed
  next
    case (ProcCallReturn p ins outs c nx p' es' rets' n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  qed
qed


lemma path_Main_SeqSecond:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" and "Rep_wf_prog wfp' = (c1;;prog,procs)"
  shows "wfp  (Main,n) -as→* (p',n'); a  set as. intra_kind (kind a); n  Entry
   wfp'  (Main,n  #:c1) -as ⊕s #:c1→* (p',n'  #:c1)"
proof(induct "(Main,n)" as "(p',n')" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main, n')
    n'  Entry Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (c1;;prog,procs)
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n'  #:c1)"
    by(fastforce intro:valid_node_Main_SeqSecond)
  with Main = p' show ?case
    by(fastforce intro:ProcCFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as a n)
  note IH = n.  n'' = (Main, n); aset as. intra_kind (kind a); n  Entry 
     wfp'  (Main, n  #:c1) -as ⊕s #:c1→* (p', n'  #:c1)
  note [simp] = Rep_wf_prog wfp = (prog,procs) Rep_wf_prog wfp' = (c1;;prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    intra_kind (kind a) wf 
  obtain nx'' where "n'' = (Main,nx'')" and "nx''  Entry"
    by(auto elim!:PCFG.cases simp:valid_edge_def intra_kind_def)
  from IH[OF n'' = (Main,nx'') aset as. intra_kind (kind a) nx''  Entry]
  have path:"wfp'  (Main, nx''  #:c1) -as ⊕s #:c1→* (p', n'  #:c1)" .
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    n'' = (Main,nx'') n  Entry intra_kind (kind a) wf
  have "c1;; prog,procs  (Main, n  #:c1) -kind a (Main, nx''  #:c1)"
    by(fastforce intro:PCFG_Main_edge_SeqSecond_source_not_Entry simp:valid_edge_def)
  with path sourcenode a = (Main, n) targetnode a = n'' n'' = (Main,nx'')
  show ?case apply(cases a) apply(clarsimp simp:label_incrs_def)
    by(auto intro:ProcCFG.Cons_path simp:valid_edge_def)
qed


subsubsection ‹From prog› to if (b) prog else c2

lemma Proc_CFG_edge_CondTrue_source_not_Entry:
  "prog  n -etp n'; n  Entry  if (b) prog else c2  n  1 -etp n'  1"
by(induct rule:Proc_CFG.induct)(fastforce intro:Proc_CFG_CondThen Proc_CFG.intros)+


lemma PCFG_Main_edge_CondTrue_source_not_Entry:
  "prog,procs  (Main,n) -et (p',n'); n  Entry; intra_kind et; well_formed procs
   if (b) prog else c2,procs  (Main,n  1) -et (p',n'  1)"
proof(induct "(Main,n)" et "(p',n')" rule:PCFG.induct)
  case Main
  thus ?case by(fastforce dest:Proc_CFG_edge_CondTrue_source_not_Entry intro:PCFG.Main)
next
  case (MainCallReturn p es rets)
  from prog  n -CEdge (p, es, rets)p n' n  Entry
  have "if (b) prog else c2  n  1 -CEdge (p, es, rets)p n'  1"
    by(rule Proc_CFG_edge_CondTrue_source_not_Entry)
  with MainCallReturn show ?case by(fastforce intro:PCFG.MainCallReturn)
qed (auto simp:intra_kind_def)


lemma valid_node_Main_CondTrue:
  fixes wfp
  assumes "CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)"
  and "n  Entry" and "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (if (b) prog else c2,procs)"
  shows "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n  1)"
proof -
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) prog else c2,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)
  obtain a where "prog,procs  sourcenode a -kind a targetnode a"
    and "(Main,n) = sourcenode a  (Main,n) = targetnode a"
    by(fastforce simp:ProcCFG.valid_node_def valid_edge_def)
  from this n  Entry wf show ?thesis
  proof(induct "sourcenode a" "kind a" "targetnode a" rule:PCFG.induct)
    case (Main nx nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -IEdge (kind a)p nx'
      have "if (b) prog else c2  n  1 -IEdge (kind a)p nx'  1"
        by(fastforce intro:Proc_CFG_edge_CondTrue_source_not_Entry)
      hence "if (b) prog else c2,procs  (Main,n  1) -kind a (Main,nx'  1)"
        by(rule PCFG.Main)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      show ?thesis
      proof(cases "nx = Entry")
        case True
        with prog  nx -IEdge (kind a)p nx'
        have "nx' = Exit  nx' = Label 0" by(fastforce dest:Proc_CFG_EntryD)
        thus ?thesis
        proof
          assume "nx' = Exit"
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis by simp
        next
          assume "nx' = Label 0"
          have "if (b) prog else c2  Label 0 
            -IEdge (λcf. state_check cf b (Some true))p Label 1"
            by(rule Proc_CFG_CondTrue)
          with nx' = Label 0 
          have "if (b) prog else c2,procs  (Main,Label 0) 
            -(λcf. state_check cf b (Some true)) (Main,nx'  1)" 
            by(fastforce intro:PCFG.Main)
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis
            by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
        qed
      next
        case False
        with prog  nx -IEdge (kind a)p nx'
        have "if (b) prog else c2  nx  1 -IEdge (kind a)p nx'  1"
          by(fastforce intro:Proc_CFG_edge_CondTrue_source_not_Entry)
        hence "if (b) prog else c2,procs  (Main,nx  1) -kind a 
          (Main,nx'  1)" by(rule PCFG.Main)
        with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
        show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
      qed
    qed
  next
    case (Proc p ins outs c nx n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCall l p es rets n' ins outs c)
    from (p, ins, outs, c)  set procs (p, Entry) = targetnode a[THEN sym] 
      (Main, Label l) = sourcenode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l" by fastforce
    from prog  Label l -CEdge (p, es, rets)p n'
    have "if (b) prog else c2  Label l  1 -CEdge (p, es, rets)p n'  1"
      by -(rule Proc_CFG_edge_CondTrue_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "if (b) prog else c2,procs  (Main,Label (l + 1)) 
      -(λs. True):(Main,n'  1)↪⇘pmap (λe cf. interpret e cf) es (p,Entry)"
      by(fastforce intro:PCFG.MainCall)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcCall p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p, Label l) = sourcenode a[THEN sym] 
      (p', Entry) = targetnode a[THEN sym] well_formed procs 
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainReturn l p es rets l' ins outs c)
    from (p, ins, outs, c)  set procs (p, Exit) = sourcenode a[THEN sym] 
      (Main, Label l') = targetnode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l'" by fastforce
    from prog  Label l -CEdge (p, es, rets)p Label l'
    have "if (b) prog else c2  Label l  1 -CEdge (p, es, rets)p Label l'  1"
      by -(rule Proc_CFG_edge_CondTrue_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "if (b) prog else c2,procs  (p,Exit) -(λcf. snd cf = (Main,Label l'  1))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (Main,Label (l' + 1))"
      by(fastforce intro:PCFG.MainReturn)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcReturn p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p', Exit) = sourcenode a[THEN sym] 
      (p, Label l') = targetnode a[THEN sym] well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCallReturn nx p es rets nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -CEdge (p, es, rets)p nx'
      have "if (b) prog else c2  n  1 -CEdge (p, es, rets)p nx'  1"
        by(fastforce intro:Proc_CFG_edge_CondTrue_source_not_Entry)
      hence "if (b) prog else c2,procs  (Main,n  1) -(λs. False) 
        (Main,nx'  1)" by -(rule PCFG.MainCallReturn)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      from prog  nx -CEdge (p, es, rets)p nx'
      have "nx  Entry" by(fastforce dest:Proc_CFG_Call_Labels)
      with prog  nx -CEdge (p, es, rets)p nx'
      have "if (b) prog else c2  nx  1 -CEdge (p, es, rets)p nx'  1"
        by(fastforce intro:Proc_CFG_edge_CondTrue_source_not_Entry)
      hence "if (b) prog else c2,procs  (Main,nx  1) -(λs. False) (Main,nx'  1)"
        by -(rule PCFG.MainCallReturn)
      with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
      show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    qed
  next
    case (ProcCallReturn p ins outs c nx p' es' rets' n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  qed
qed


lemma path_Main_CondTrue:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (if (b) prog else c2,procs)"
  shows "wfp  (Main,n) -as→* (p',n'); a  set as. intra_kind (kind a); n  Entry
   wfp'  (Main,n  1) -as ⊕s 1→* (p',n'  1)"
proof(induct "(Main,n)" as "(p',n')" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main, n')
    n'  Entry Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) prog else c2,procs)
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n'  1)" 
    by(fastforce intro:valid_node_Main_CondTrue)
  with Main = p' show ?case
    by(fastforce intro:ProcCFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as a n)
  note IH = n.  n'' = (Main, n); aset as. intra_kind (kind a); n  Entry 
     wfp'  (Main, n  1) -as ⊕s 1→* (p', n'  1)
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) prog else c2,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    intra_kind (kind a) wf 
  obtain nx'' where "n'' = (Main,nx'')" and "nx''  Entry"
    by(auto elim!:PCFG.cases simp:valid_edge_def intra_kind_def)
  from IH[OF n'' = (Main,nx'') aset as. intra_kind (kind a) nx''  Entry]
  have path:"wfp'  (Main, nx''  1) -as ⊕s 1→* (p', n'  1)" .
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    n'' = (Main,nx'') n  Entry intra_kind (kind a) wf
  have "if (b) prog else c2,procs  (Main, n  1) -kind a (Main, nx''  1)"
    by(fastforce intro:PCFG_Main_edge_CondTrue_source_not_Entry simp:valid_edge_def)
  with path sourcenode a = (Main, n) targetnode a = n'' n'' = (Main,nx'')
  show ?case
    apply(cases a) apply(clarsimp simp:label_incrs_def)
    by(auto intro:ProcCFG.Cons_path simp:valid_edge_def)
qed


subsubsection ‹From prog› to if (b) c1 else prog›

lemma Proc_CFG_edge_CondFalse_source_not_Entry:
  "prog  n -etp n'; n  Entry 
   if (b) c1 else prog  n  (#:c1 + 1) -etp n'  (#:c1 + 1)"
by(induct rule:Proc_CFG.induct)(fastforce intro:Proc_CFG_CondElse Proc_CFG.intros)+


lemma PCFG_Main_edge_CondFalse_source_not_Entry:
  "prog,procs  (Main,n) -et (p',n'); n  Entry; intra_kind et; well_formed procs
   if (b) c1 else prog,procs  (Main,n  (#:c1 + 1)) -et (p',n'  (#:c1 + 1))"
proof(induct "(Main,n)" et "(p',n')" rule:PCFG.induct)
  case Main
  thus ?case 
    by(fastforce dest:Proc_CFG_edge_CondFalse_source_not_Entry intro:PCFG.Main)
next
  case (MainCallReturn p es rets)
  from prog  n -CEdge (p, es, rets)p n' n  Entry
  have "if (b) c1 else prog  n  (#:c1 + 1) -CEdge (p, es, rets)p n'  (#:c1 + 1)"
    by(rule Proc_CFG_edge_CondFalse_source_not_Entry)
  with MainCallReturn show ?case by(fastforce intro:PCFG.MainCallReturn)
qed (auto simp:intra_kind_def)


lemma valid_node_Main_CondFalse:
  fixes wfp
  assumes "CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)"
  and "n  Entry" and "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (if (b) c1 else prog,procs)"
  shows "CFG.valid_node sourcenode targetnode (valid_edge wfp') 
  (Main, n  (#:c1 + 1))"
proof -
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) c1 else prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)
  obtain a where "prog,procs  sourcenode a -kind a targetnode a"
    and "(Main,n) = sourcenode a  (Main,n) = targetnode a"
    by(fastforce simp:ProcCFG.valid_node_def valid_edge_def)
  from this n  Entry wf show ?thesis
  proof(induct "sourcenode a" "kind a" "targetnode a" rule:PCFG.induct)
    case (Main nx nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -IEdge (kind a)p nx'
      have "if (b) c1 else prog  n  (#:c1 + 1) -IEdge (kind a)p nx'  (#:c1 + 1)"
        by(fastforce intro:Proc_CFG_edge_CondFalse_source_not_Entry)
      hence "if (b) c1 else prog,procs  (Main,n  (#:c1 + 1)) -kind a 
        (Main,nx'  (#:c1 + 1))" by(rule PCFG.Main)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      show ?thesis
      proof(cases "nx = Entry")
        case True
        with prog  nx -IEdge (kind a)p nx' 
        have "nx' = Exit  nx' = Label 0" by(fastforce dest:Proc_CFG_EntryD)
        thus ?thesis
        proof
          assume "nx' = Exit"
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis by simp
        next
          assume "nx' = Label 0"
          have "if (b) c1 else prog  Label 0 
            -IEdge (λcf. state_check cf b (Some false))p Label (#:c1 + 1)"
            by(rule Proc_CFG_CondFalse)
          with nx' = Label 0 
          have "if (b) c1 else prog,procs  (Main,Label 0) 
            -(λcf. state_check cf b (Some false)) (Main,nx'  (#:c1 + 1))" 
            by(fastforce intro:PCFG.Main)
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis
            by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
        qed
      next
        case False
        with prog  nx -IEdge (kind a)p nx'
        have "if (b) c1 else prog  nx  (#:c1 + 1) -IEdge (kind a)p nx'  (#:c1 + 1)"
          by(fastforce intro:Proc_CFG_edge_CondFalse_source_not_Entry)
        hence "if (b) c1 else prog,procs  (Main,nx  (#:c1 + 1)) -kind a 
          (Main,nx'  (#:c1 + 1))" by(rule PCFG.Main)
        with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym] 
        show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
      qed
    qed
  next
    case (Proc p ins outs c nx n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCall l p es rets n' ins outs c)
    from (p, ins, outs, c)  set procs (p, Entry) = targetnode a[THEN sym]
      (Main, Label l) = sourcenode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l" by fastforce
    from prog  Label l -CEdge (p, es, rets)p n'
    have "if (b) c1 else prog  Label l  (#:c1 + 1) -CEdge (p, es, rets)p 
      n'  (#:c1 + 1)" by -(rule Proc_CFG_edge_CondFalse_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "if (b) c1 else prog,procs  (Main,Label (l + (#:c1 + 1))) 
      -(λs. True):(Main,n'  (#:c1 + 1))↪⇘pmap (λe cf. interpret e cf) es (p,Entry)"
      by(fastforce intro:PCFG.MainCall)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcCall p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p, Label l) = sourcenode a[THEN sym]
      (p', Entry) = targetnode a[THEN sym]  well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainReturn l p es rets l' ins outs c)
    from (p, ins, outs, c)  set procs (p, Exit) = sourcenode a[THEN sym]
      (Main, Label l') = targetnode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l'" by fastforce
    from prog  Label l -CEdge (p, es, rets)p Label l'
    have "if (b) c1 else prog  Label l  (#:c1 + 1) -CEdge (p, es, rets)p 
      Label l'  (#:c1 + 1)" by -(rule Proc_CFG_edge_CondFalse_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "if (b) c1 else prog,procs  (p,Exit) 
      -(λcf. snd cf = (Main,Label l'  (#:c1 + 1)))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (Main,Label (l' + (#:c1 + 1)))"
      by(fastforce intro:PCFG.MainReturn)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcReturn p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p', Exit) = sourcenode a[THEN sym] 
      (p, Label l') = targetnode a[THEN sym] well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCallReturn nx p es rets nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from n  Entry prog  nx -CEdge (p, es, rets)p nx'
      have "if (b) c1 else prog  n  (#:c1 + 1) -CEdge (p, es, rets)p 
        nx'  (#:c1 + 1)" by(fastforce intro:Proc_CFG_edge_CondFalse_source_not_Entry)
      hence "if (b) c1 else prog,procs  (Main,n  (#:c1 + 1)) 
        -(λs. False) (Main,nx'  (#:c1 + 1))" by -(rule PCFG.MainCallReturn)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      from prog  nx -CEdge (p, es, rets)p nx'
      have "nx  Entry" by(fastforce dest:Proc_CFG_Call_Labels)
      with prog  nx -CEdge (p, es, rets)p nx'
      have "if (b) c1 else prog  nx  (#:c1 + 1) -CEdge (p, es, rets)p 
        nx'  (#:c1 + 1)" by(fastforce intro:Proc_CFG_edge_CondFalse_source_not_Entry)
      hence "if (b) c1 else prog,procs  (Main,nx  (#:c1 + 1)) 
        -(λs. False) (Main,nx'  (#:c1 + 1))" by -(rule PCFG.MainCallReturn)
      with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
      show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    qed
  next
    case (ProcCallReturn p ins outs c nx p' es' rets' n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  qed
qed


lemma path_Main_CondFalse:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (if (b) c1 else prog,procs)"
  shows "wfp  (Main,n) -as→* (p',n'); a  set as. intra_kind (kind a); n  Entry
   wfp'  (Main,n  (#:c1 + 1)) -as ⊕s (#:c1 + 1)→* (p',n'  (#:c1 + 1))"
proof(induct "(Main,n)" as "(p',n')" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main, n')
    n'  Entry Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) c1 else prog,procs)
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n'  (#:c1 + 1))"
    by(fastforce intro:valid_node_Main_CondFalse)
  with Main = p' show ?case
    by(fastforce intro:ProcCFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as a n)
  note IH = n. n.  n'' = (Main, n); aset as. intra_kind (kind a); n  Entry
     wfp'  (Main, n  (#:c1 + 1)) -as ⊕s (#:c1 + 1)→* (p', n'  (#:c1 + 1))
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (if (b) c1 else prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    intra_kind (kind a) wf 
  obtain nx'' where "n'' = (Main,nx'')" and "nx''  Entry"
    by(auto elim!:PCFG.cases simp:valid_edge_def intra_kind_def)
  from IH[OF n'' = (Main,nx'') aset as. intra_kind (kind a) nx''  Entry]
  have path:"wfp'  (Main, nx''  (#:c1 + 1)) -as ⊕s (#:c1 + 1)→* 
    (p', n'  (#:c1 + 1))" .
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    n'' = (Main,nx'') n  Entry intra_kind (kind a) wf
  have "if (b) c1 else prog,procs  (Main, n  (#:c1 + 1)) -kind a 
    (Main, nx''  (#:c1 + 1))"
    by(fastforce intro:PCFG_Main_edge_CondFalse_source_not_Entry simp:valid_edge_def)
  with path sourcenode a = (Main, n) targetnode a = n'' n'' = (Main,nx'')
  show ?case
    apply(cases a) apply(clarsimp simp:label_incrs_def)
    by(auto intro:ProcCFG.Cons_path simp:valid_edge_def)
qed


subsubsection ‹From prog› to while (b) prog›

lemma Proc_CFG_edge_WhileBody_source_not_Entry:
  "prog  n -etp n'; n  Entry; n'  Exit 
   while (b) prog  n  2 -etp n'  2"
by(induct rule:Proc_CFG.induct)(fastforce intro:Proc_CFG_WhileBody Proc_CFG.intros)+


lemma PCFG_Main_edge_WhileBody_source_not_Entry:
  "prog,procs  (Main,n) -et (p',n'); n  Entry; n'  Exit; intra_kind et; 
  well_formed procs  while (b) prog,procs  (Main,n  2) -et (p',n'  2)"
proof(induct "(Main,n)" et "(p',n')" rule:PCFG.induct)
  case Main
  thus ?case 
    by(fastforce dest:Proc_CFG_edge_WhileBody_source_not_Entry intro:PCFG.Main)
next
  case (MainCallReturn p es rets)
  from prog  n -CEdge (p, es, rets)p n' n  Entry n'  Exit
  have "while (b) prog  n  2 -CEdge (p, es, rets)p n'  2"
    by(rule Proc_CFG_edge_WhileBody_source_not_Entry)
  with MainCallReturn show ?case by(fastforce intro:PCFG.MainCallReturn)
qed (auto simp:intra_kind_def)


lemma valid_node_Main_WhileBody:
  fixes wfp
  assumes "CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)"
  and "n  Entry" and "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (while (b) prog,procs)"
  shows "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n  2)"
proof -
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
    Rep_wf_prog wfp' = (while (b) prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main,n)
  obtain a where "prog,procs  sourcenode a -kind a targetnode a"
    and "(Main,n) = sourcenode a  (Main,n) = targetnode a"
    by(fastforce simp:ProcCFG.valid_node_def valid_edge_def)
  from this n  Entry wf show ?thesis
  proof(induct "sourcenode a" "kind a" "targetnode a" rule:PCFG.induct)
    case (Main nx nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      show ?thesis
      proof(cases "nx' = Exit")
        case True
        with n  Entry prog  nx -IEdge (kind a)p nx'
        have "while (b) prog  n  2 -IEdge (kind a)p Label 0"
          by(fastforce intro:Proc_CFG_WhileBodyExit)
        hence "while (b) prog,procs  (Main,n  2) -kind a (Main,Label 0)"
          by(rule PCFG.Main)
        thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
      next
        case False
        with n  Entry prog  nx -IEdge (kind a)p nx'
        have "while (b) prog  n  2 -IEdge (kind a)p nx'  2"
          by(fastforce intro:Proc_CFG_edge_WhileBody_source_not_Entry)
        hence "while (b) prog,procs  (Main,n  2) -kind a (Main,nx'  2)"
          by(rule PCFG.Main)
        thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
      qed
    next
      assume "(Main, n) = targetnode a"
      show ?thesis
      proof(cases "nx = Entry")
        case True
        with prog  nx -IEdge (kind a)p nx' 
        have "nx' = Exit  nx' = Label 0" by(fastforce dest:Proc_CFG_EntryD)
        thus ?thesis
        proof
          assume "nx' = Exit"
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis by simp
        next
          assume "nx' = Label 0"
          have "while (b) prog  Label 0 
            -IEdge (λcf. state_check cf b (Some true))p Label 2"
            by(rule Proc_CFG_WhileTrue)
          hence "while (b) prog,procs  (Main,Label 0) 
            -(λcf. state_check cf b (Some true)) (Main,Label 2)"
            by(fastforce intro:PCFG.Main)
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
            nx' = Label 0 show ?thesis
            by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
        qed
      next
        case False
        show ?thesis
        proof(cases "nx' = Exit")
          case True
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis by simp
        next
          case False
          with prog  nx -IEdge (kind a)p nx' nx  Entry
          have "while (b) prog  nx  2 -IEdge (kind a)p nx'  2"
            by(fastforce intro:Proc_CFG_edge_WhileBody_source_not_Entry)
          hence "while (b) prog,procs  (Main,nx  2)  -kind a 
            (Main,nx'  2)" by(rule PCFG.Main)
          with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym]
          show ?thesis
            by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
        qed
      qed
    qed
  next
    case (Proc p ins outs c nx n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (Main, n) = sourcenode a  (Main, n) = targetnode a 
      (p, ins, outs, c)  set procs well_formed procs 
    have False by fastforce
    thus ?case by simp
  next
    case (MainCall l p es rets n' ins outs c)
    from (p, ins, outs, c)  set procs (p, Entry) = targetnode a[THEN sym]
      (Main, Label l) = sourcenode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l" by fastforce
    from prog  Label l -CEdge (p, es, rets)p n' have "n'  Exit"
      by(fastforce dest:Proc_CFG_Call_Labels)
    with prog  Label l -CEdge (p, es, rets)p n'
    have "while (b) prog  Label l  2 -CEdge (p, es, rets)p 
      n'  2" by -(rule Proc_CFG_edge_WhileBody_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "while (b) prog,procs  (Main,Label l  2) 
      -(λs. True):(Main,n'  2)↪⇘pmap (λe cf. interpret e cf) es (p,Entry)"
      by(fastforce intro:PCFG.MainCall)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcCall p ins outs c l p' es' rets' l' ins' outs' c')
    from (p, Label l) = sourcenode a[THEN sym]
      (p', Entry) = targetnode a[THEN sym]  well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainReturn l p es rets l' ins outs c)
    from (p, ins, outs, c)  set procs (p, Exit) = sourcenode a[THEN sym]
      (Main, Label l') = targetnode a[THEN sym] wf
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have [simp]:"n = Label l'" by fastforce
    from prog  Label l -CEdge (p, es, rets)p Label l'
    have "while (b) prog  Label l  2 -CEdge (p, es, rets)p 
      Label l'  2" by -(rule Proc_CFG_edge_WhileBody_source_not_Entry,auto)
    with (p, ins, outs, c)  set procs
    have "while (b) prog,procs  (p,Exit) -(λcf. snd cf = (Main,Label l'  2))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (Main,Label l'  2)"
      by(fastforce intro:PCFG.MainReturn)
    thus ?case by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
  next
    case (ProcReturn p ins outs c l p' es' rets' l' ins' outs' c' ps)
    from (p', Exit) = sourcenode a[THEN sym] 
      (p, Label l') = targetnode a[THEN sym] well_formed procs
      (p, ins, outs, c)  set procs (p', ins', outs', c')  set procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  next
    case (MainCallReturn nx p es rets nx')
    from (Main,n) = sourcenode a  (Main,n) = targetnode a show ?case
    proof
      assume "(Main,n) = sourcenode a"
      with (Main, nx) = sourcenode a[THEN sym] have [simp]:"nx = n" by simp
      from prog  nx -CEdge (p, es, rets)p nx' have "nx'  Exit"
        by(fastforce dest:Proc_CFG_Call_Labels)
      with n  Entry prog  nx -CEdge (p, es, rets)p nx'
      have "while (b) prog  n  2 -CEdge (p, es, rets)p 
        nx'  2" by(fastforce intro:Proc_CFG_edge_WhileBody_source_not_Entry)
      hence "while (b) prog,procs  (Main,n  2) -(λs. False) (Main,nx'  2)"
        by -(rule PCFG.MainCallReturn)
      thus ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    next
      assume "(Main, n) = targetnode a"
      from prog  nx -CEdge (p, es, rets)p nx'
      have "nx  Entry" and "nx'  Exit" by(auto dest:Proc_CFG_Call_Labels)
      with prog  nx -CEdge (p, es, rets)p nx'
      have "while (b) prog  nx  2 -CEdge (p, es, rets)p 
        nx'  2" by(fastforce intro:Proc_CFG_edge_WhileBody_source_not_Entry)
      hence "while (b) prog,procs  (Main,nx  2) -(λs. False) (Main,nx'  2)"
        by -(rule PCFG.MainCallReturn)
      with (Main, n) = targetnode a (Main, nx') = targetnode a[THEN sym] 
      show ?thesis by(simp add:ProcCFG.valid_node_def)(fastforce simp:valid_edge_def)
    qed
  next
    case (ProcCallReturn p ins outs c nx p' es' rets' n' ps)
    from (p, nx) = sourcenode a[THEN sym] (p, n') = targetnode a[THEN sym]
      (p, ins, outs, c)  set procs well_formed procs
      (Main, n) = sourcenode a  (Main, n) = targetnode a
    have False by fastforce
    thus ?case by simp
  qed
qed


lemma path_Main_WhileBody:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" 
  and "Rep_wf_prog wfp' = (while (b) prog,procs)"
  shows "wfp  (Main,n) -as→* (p',n'); a  set as. intra_kind (kind a); 
    n  Entry; n'  Exit  wfp'  (Main,n  2) -as ⊕s 2→* (p',n'  2)"
proof(induct "(Main,n)" as "(p',n')" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from CFG.valid_node sourcenode targetnode (valid_edge wfp) (Main, n')
    n'  Entry Rep_wf_prog wfp = (prog,procs)
    Rep_wf_prog wfp' = (while (b) prog,procs)
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n'  2)" 
    by(fastforce intro:valid_node_Main_WhileBody)
  with Main = p' show ?case
    by(fastforce intro:ProcCFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as a n)
  note IH = n.  n'' = (Main, n); aset as. intra_kind (kind a); n  Entry; 
    n'  Exit  wfp'  (Main, n  2) -as ⊕s 2→* (p', n'  2)
  note [simp] = Rep_wf_prog wfp = (prog,procs) 
     Rep_wf_prog wfp' = (while (b) prog,procs)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    intra_kind (kind a) wf 
  obtain nx'' where "n'' = (Main,nx'')" and "nx''  Entry"
    by(auto elim!:PCFG.cases simp:valid_edge_def intra_kind_def)
  from IH[OF n'' = (Main,nx'') aset as. intra_kind (kind a) 
    nx''  Entry n'  Exit]
  have path:"wfp'  (Main, nx''  2) -as ⊕s 2→* (p', n'  2)" .
  with n'  Exit have "nx''  Exit" by(fastforce dest:ProcCFGExit.path_Exit_source)
  with valid_edge wfp a sourcenode a = (Main, n) targetnode a = n''
    n'' = (Main,nx'') n  Entry intra_kind (kind a) wf
  have "while (b) prog,procs  (Main, n  2) -kind a (Main, nx''  2)"
    by(fastforce intro:PCFG_Main_edge_WhileBody_source_not_Entry simp:valid_edge_def)
  with path sourcenode a = (Main, n) targetnode a = n'' n'' = (Main,nx'')
  show ?case
    apply(cases a) apply(clarsimp simp:label_incrs_def)
    by(auto intro:ProcCFG.Cons_path simp:valid_edge_def)
qed


subsubsection ‹Existence of intraprodecural paths›

lemma Label_Proc_CFG_Entry_Exit_path_Main:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" and "l < #:prog"
  obtains as as' where "wfp  (Main,Label l) -as→* (Main,Exit)"
  and "a  set as. intra_kind (kind a)"
  and "wfp  (Main,Entry) -as'→* (Main,Label l)"
  and "a  set as'. intra_kind (kind a)"
proof(atomize_elim)
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from l < #:prog Rep_wf_prog wfp = (prog,procs)
  show "as as'. wfp  (Main, Label l) -as→* (Main, Exit) 
    (aset as. intra_kind (kind a)) 
    wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))"
  proof(induct prog arbitrary:l wfp)
    case Skip
    note [simp] = Rep_wf_prog wfp = (Skip, procs)
    from l < #:Skip have [simp]:"l = 0" by simp
    have "wfp  (Main,Entry) -[((Main,Entry),(λs. True),(Main,Label 0))]→* 
      (Main,Label 0)" 
      by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_Entry
                   simp:valid_edge_def ProcCFG.valid_node_def)
    moreover
    have "wfp  (Main,Label l) -[((Main,Label l),id,(Main,Exit))]→* (Main,Exit)" 
      by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_Skip simp:valid_edge_def)
    ultimately show ?case by(fastforce simp:intra_kind_def)
  next
    case (LAss V e)
    note [simp] = Rep_wf_prog wfp = (V:=e, procs)
    from l < #:V:=e have "l = 0  l = 1" by auto
    thus ?case
    proof
      assume [simp]:"l = 0"
      have "wfp  (Main,Entry) -[((Main,Entry),(λs. True),(Main,Label 0))]→*
        (Main,Label 0)" 
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_Entry
                    simp:valid_edge_def ProcCFG.valid_node_def)
      moreover
      have "wfp  (Main,Label 0) 
        -((Main,Label 0),(λcf. update cf V e),(Main,Label 1))#
        [((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
        by(fastforce intro:ProcCFG.Cons_path ProcCFG.path.intros Main Proc_CFG_LAss 
          Proc_CFG_LAssSkip simp:valid_edge_def ProcCFG.valid_node_def)
      ultimately show ?thesis by(fastforce simp:intra_kind_def)
    next
      assume [simp]:"l = 1"
      have "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
        [((Main,Label 0),(λcf. update cf V e),(Main,Label 1))]→* (Main,Label 1)"
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_LAss ProcCFG.Cons_path 
          Main Proc_CFG_Entry simp:ProcCFG.valid_node_def valid_edge_def)
      moreover
      have "wfp  (Main,Label 1) -[((Main,Label 1),id,(Main,Exit))]→* 
        (Main,Exit)" by(fastforce intro:ProcCFG.path.intros  Main Proc_CFG_LAssSkip
        simp:valid_edge_def ProcCFG.valid_node_def)
      ultimately show ?thesis by(fastforce simp:intra_kind_def)
    qed
  next
    case (Seq c1 c2)
    note IH1 = l wfp. l < #:c1; Rep_wf_prog wfp = (c1, procs) 
      as as'. wfp  (Main, Label l) -as→* (Main, Exit)  
      (aset as. intra_kind (kind a)) 
      wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))
    note IH2 = l wfp. l < #:c2; Rep_wf_prog wfp = (c2, procs) 
      as as'. wfp  (Main, Label l) -as→* (Main, Exit)  
      (aset as. intra_kind (kind a)) 
      wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))
    note [simp] = Rep_wf_prog wfp = (c1;; c2, procs)
    show ?case
    proof(cases "l < #:c1")
      case True
      from Rep_wf_prog wfp = (c1;; c2, procs)
      obtain wfp' where [simp]:"Rep_wf_prog wfp' = (c1, procs)" by(erule wfp_Seq1)
      from IH1[OF True this] obtain as as' 
        where path1:"wfp'  (Main, Label l) -as→* (Main, Exit)"
        and intra1:"aset as. intra_kind (kind a)"
        and path2:"wfp'  (Main, Entry) -as'→* (Main, Label l)"
        and intra2:"aset as'. intra_kind (kind a)" by blast
      from path1 have "as  []" by(fastforce elim:ProcCFG.path.cases)
      then obtain ax asx where [simp]:"as = asx@[ax]"
        by(cases as rule:rev_cases) fastforce+
      with path1 have "wfp'  (Main, Label l) -asx→* sourcenode ax"
        and "valid_edge wfp' ax" and "targetnode ax = (Main, Exit)"
        by(auto elim:ProcCFG.path_split_snoc)
      from valid_edge wfp' ax targetnode ax = (Main, Exit)
      obtain nx where "sourcenode ax = (Main,nx)" 
        by(fastforce elim:PCFG.cases simp:valid_edge_def)
      with wfp'  (Main, Label l) -asx→* sourcenode ax have "nx  Entry"
        by fastforce
      moreover
      from valid_edge wfp' ax sourcenode ax = (Main,nx) have "nx  Exit"
        by(fastforce intro:ProcCFGExit.Exit_source)
      ultimately obtain lx where [simp]:"nx = Label lx" by(cases nx) auto
      with wfp'  (Main, Label l) -asx→* sourcenode ax 
        sourcenode ax = (Main,nx) intra1
      have path3:"wfp  (Main, Label l) -asx→* (Main, Label lx)"
        by -(rule path_SeqFirst,auto)
      from valid_edge wfp' ax targetnode ax = (Main, Exit)
        sourcenode ax = (Main,nx) wf
      obtain etx where "c1  Label lx -etxp Exit" 
        by(fastforce elim!:PCFG.cases simp:valid_edge_def)
      then obtain et where [simp]:"etx = IEdge et" 
        by(cases etx)(auto dest:Proc_CFG_Call_Labels)
      with c1  Label lx -etxp Exit have "intra_kind et"
        by(fastforce intro:Proc_CFG_IEdge_intra_kind)
      from c1  Label lx -etxp Exit path3
      have path4:"wfp  (Main, Label l) -asx@
        [((Main, Label lx),et,(Main,Label 0  #:c1))] →* (Main,Label 0  #:c1)"
        by(fastforce intro:ProcCFG.path_Append ProcCFG.path.intros Proc_CFG_SeqConnect
          Main simp:ProcCFG.valid_node_def valid_edge_def)
      from Rep_wf_prog wfp = (c1;; c2, procs)
      obtain wfp'' where [simp]:"Rep_wf_prog wfp'' = (c2, procs)" by(erule wfp_Seq2)
      from IH2[OF _ this,of "0"] obtain asx' 
        where "wfp''  (Main, Label 0) -asx'→* (Main, Exit)"
        and "aset asx'. intra_kind (kind a)" by blast
      with path4 intra1 intra_kind et have "wfp  (Main, Label l) 
        -(asx@[((Main, Label lx),et,(Main,Label 0  #:c1))])@(asx' ⊕s #:c1)→*
        (Main, Exit  #:c1)"
        by -(erule ProcCFG.path_Append,rule path_Main_SeqSecond,auto)
      moreover
      from intra1 intra_kind et aset asx'. intra_kind (kind a)
      have "a  set ((asx@[((Main, Label lx),et,(Main,Label #:c1))])@(asx' ⊕s #:c1)).
        intra_kind (kind a)" by(auto simp:label_incrs_def)
      moreover
      from path2 intra2 have "wfp  (Main, Entry) -as'→* (Main, Label l)"
        by -(rule path_SeqFirst,auto)
      ultimately show ?thesis using aset as'. intra_kind (kind a) by fastforce
    next
      case False
      hence "#:c1  l" by simp
      then obtain l' where [simp]:"l = l' + #:c1" and "l' = l - #:c1" by simp
      from l < #:c1;; c2 have "l' < #:c2" by simp
      from Rep_wf_prog wfp = (c1;; c2, procs)
      obtain wfp' where [simp]:"Rep_wf_prog wfp' = (c2, procs)" by(erule wfp_Seq2)
      from IH2[OF l' < #:c2 this] obtain as as' 
        where path1:"wfp'  (Main, Label l') -as→* (Main, Exit)"
        and intra1:"aset as. intra_kind (kind a)"
        and path2:"wfp'  (Main, Entry) -as'→* (Main, Label l')"
        and intra2:"aset as'. intra_kind (kind a)" by blast
      from path1 intra1
      have "wfp  (Main, Label l'  #:c1) -as ⊕s #:c1→* (Main, Exit  #:c1)"
        by -(rule path_Main_SeqSecond,auto)
      moreover
      from path2 have "as'  []" by(fastforce elim:ProcCFG.path.cases)
      with path2 obtain ax' asx' where [simp]:"as' = ax'#asx'"
        and "sourcenode ax' = (Main, Entry)" and "valid_edge wfp' ax'" 
        and "wfp'  targetnode ax' -asx'→* (Main, Label l')"
        by -(erule ProcCFG.path_split_Cons,fastforce+)
      from wfp'  targetnode ax' -asx'→* (Main, Label l')
      have "targetnode ax'  (Main,Exit)" by fastforce
      with valid_edge wfp' ax' sourcenode ax' = (Main, Entry) wf
      have "targetnode ax' = (Main,Label 0)"
        by(fastforce elim:PCFG.cases dest:Proc_CFG_EntryD simp:valid_edge_def)
      with wfp'  targetnode ax' -asx'→* (Main, Label l') intra2
      have path3:"wfp  (Main,Label 0  #:c1) -asx' ⊕s #:c1→* 
        (Main, Label l'  #:c1)" by -(rule path_Main_SeqSecond,auto)
      from Rep_wf_prog wfp = (c1;; c2, procs)
      obtain wfp'' where [simp]:"Rep_wf_prog wfp'' = (c1, procs)" by(erule wfp_Seq1)
      from IH1[OF _ this,of "0"] obtain xs 
        where "wfp''  (Main, Label 0) -xs→* (Main, Exit)"
        and "aset xs. intra_kind (kind a)" by blast
      from wfp''  (Main, Label 0) -xs→* (Main, Exit) have "xs  []"
        by(fastforce elim:ProcCFG.path.cases)
      then obtain x xs' where [simp]:"xs = xs'@[x]"
        by(cases xs rule:rev_cases) fastforce+
      with wfp''  (Main, Label 0) -xs→* (Main, Exit)
      have "wfp''  (Main, Label 0) -xs'→* sourcenode x"
        and "valid_edge wfp'' x" and "targetnode x = (Main, Exit)"
        by(auto elim:ProcCFG.path_split_snoc)
      from valid_edge wfp'' x targetnode x = (Main, Exit)
      obtain nx where "sourcenode x = (Main,nx)" 
        by(fastforce elim:PCFG.cases simp:valid_edge_def)
      with wfp''  (Main, Label 0) -xs'→* sourcenode x have "nx  Entry"
        by fastforce
      from valid_edge wfp'' x sourcenode x = (Main,nx) have "nx  Exit"
        by(fastforce intro:ProcCFGExit.Exit_source)
      with nx  Entry obtain lx where [simp]:"nx = Label lx" by(cases nx) auto
      from wfp''  (Main, Label 0) -xs'→* sourcenode x 
        sourcenode x = (Main,nx) aset xs. intra_kind (kind a)
      have "wfp  (Main, Entry) 
        -((Main, Entry),(λs. True),(Main, Label 0))#xs'→* sourcenode x"
        apply simp apply(rule path_SeqFirst[OF Rep_wf_prog wfp'' = (c1, procs)])
        apply(auto intro!:ProcCFG.Cons_path)
        by(auto intro:Main Proc_CFG_Entry simp:valid_edge_def intra_kind_def)
      with valid_edge wfp'' x targetnode x = (Main, Exit) path3
        sourcenode x = (Main,nx) nx  Entry sourcenode x = (Main,nx) wf
      have "wfp  (Main, Entry) -((((Main, Entry),(λs. True),(Main, Label 0))#xs')@
        [(sourcenode x,kind x,(Main,Label #:c1))])@(asx' ⊕s #:c1)→* 
        (Main, Label l'  #:c1)" 
        by(fastforce intro:ProcCFG.path_Append ProcCFG.path.intros Main 
          Proc_CFG_SeqConnect elim!:PCFG.cases dest:Proc_CFG_Call_Labels
          simp:ProcCFG.valid_node_def valid_edge_def)
      ultimately show ?thesis using intra1 intra2 aset xs. intra_kind (kind a)
        by(fastforce simp:label_incrs_def intra_kind_def)
    qed
  next
    case (Cond b c1 c2)
    note IH1 = l wfp. l < #:c1; Rep_wf_prog wfp = (c1, procs) 
      as as'. wfp  (Main, Label l) -as→* (Main, Exit)  
      (aset as. intra_kind (kind a)) 
      wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))
    note IH2 = l wfp. l < #:c2; Rep_wf_prog wfp = (c2, procs) 
      as as'. wfp  (Main, Label l) -as→* (Main, Exit)  
      (aset as. intra_kind (kind a)) 
      wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))
    note [simp] = Rep_wf_prog wfp = (if (b) c1 else c2, procs)
    show ?case
    proof(cases "l = 0")
      case True
      from Rep_wf_prog wfp = (if (b) c1 else c2, procs)
      obtain wfp' where [simp]:"Rep_wf_prog wfp' = (c1, procs)" by(erule wfp_CondTrue)
      from IH1[OF _ this,of 0] obtain as 
        where path:"wfp'  (Main, Label 0) -as→* (Main, Exit)"
        and intra:"aset as. intra_kind (kind a)" by blast
      have "if (b) c1 else c2,procs  (Main,Label 0)
        -(λcf. state_check cf b (Some true)) (Main,Label 0  1)"
        by(fastforce intro:Main Proc_CFG_CondTrue)
      with path intra have "wfp  (Main,Label 0)
        -[((Main,Label 0),(λcf. state_check cf b (Some true)),(Main,Label 0  1))]@
        (as ⊕s 1)→* (Main,Exit  1)"
        apply - apply(rule ProcCFG.path_Append) apply(rule ProcCFG.path.intros)+
        prefer 5 apply(rule path_Main_CondTrue)
        apply(auto intro:ProcCFG.path.intros simp:valid_edge_def)
        by(fastforce simp:ProcCFG.valid_node_def valid_edge_def)
      moreover
      have "if (b) c1 else c2,procs  (Main,Entry) -(λs. True) 
        (Main,Label 0)" by(fastforce intro:Main Proc_CFG_Entry)
      hence "wfp  (Main,Entry) -[((Main,Entry),(λs. True),(Main,Label 0))]→* 
        (Main,Label 0)"
        by(fastforce intro:ProcCFG.path.intros 
                    simp:ProcCFG.valid_node_def valid_edge_def)
      ultimately show ?thesis using l = 0 aset as. intra_kind (kind a) 
        by(fastforce simp:label_incrs_def intra_kind_def)
    next
      case False
      hence "0 < l" by simp
      then obtain l' where [simp]:"l = l' + 1" and "l' = l - 1" by simp
      show ?thesis
      proof(cases "l' < #:c1")
        case True
        from Rep_wf_prog wfp = (if (b) c1 else c2, procs)
        obtain wfp' where [simp]:"Rep_wf_prog wfp' = (c1, procs)" 
          by(erule wfp_CondTrue)
        from IH1[OF True this] obtain as as' 
          where path1:"wfp'  (Main, Label l') -as→* (Main, Exit)"
          and intra1:"aset as. intra_kind (kind a)"
          and path2:"wfp'  (Main, Entry) -as'→* (Main, Label l')"
          and intra2:"aset as'. intra_kind (kind a)" by blast
        from path1 intra1
        have "wfp  (Main, Label l'  1) -as ⊕s 1→* (Main, Exit  1)"
          by -(rule path_Main_CondTrue,auto)
        moreover
        from path2 obtain ax' asx' where [simp]:"as' = ax'#asx'"
          and "sourcenode ax' = (Main,Entry)" and "valid_edge wfp' ax'"
          and "wfp'  targetnode ax' -asx'→* (Main, Label l')"
          by -(erule ProcCFG.path.cases,fastforce+)
        with wf have "targetnode ax' = (Main,Label 0)"
          by(fastforce elim:PCFG.cases dest:Proc_CFG_EntryD Proc_CFG_Call_Labels 
                      simp:valid_edge_def)
        with wfp'  targetnode ax' -asx'→* (Main, Label l') intra2
        have "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
          ((Main,Label 0),(λcf. state_check cf b (Some true)),(Main,Label 0  1))#
          (asx' ⊕s 1)→* (Main,Label l'  1)"
          apply - apply(rule ProcCFG.path.intros)+ apply(rule path_Main_CondTrue) 
          by(auto intro:Main Proc_CFG_Entry Proc_CFG_CondTrue simp:valid_edge_def)
        ultimately show ?thesis using intra1 intra2
          by(fastforce simp:label_incrs_def intra_kind_def)
      next
        case False
        hence "#:c1  l'" by simp
        then obtain l'' where [simp]:"l' = l'' + #:c1" and "l'' = l' - #:c1" by simp
        from  l < #:(if (b) c1 else c2) have "l'' < #:c2" by simp
        from Rep_wf_prog wfp = (if (b) c1 else c2, procs)
        obtain wfp'' where [simp]:"Rep_wf_prog wfp'' = (c2, procs)" 
          by(erule wfp_CondFalse)
        from IH2[OF l'' < #:c2 this] obtain as as' 
          where path1:"wfp''  (Main, Label l'') -as→* (Main, Exit)"
          and intra1:"aset as. intra_kind (kind a)"
          and path2:"wfp''  (Main, Entry) -as'→* (Main, Label l'')"
          and intra2:"aset as'. intra_kind (kind a)" by blast
        from path1 intra1
        have "wfp  (Main, Label l''  (#:c1 + 1)) -as ⊕s (#:c1 + 1)→* 
          (Main, Exit  (#:c1 + 1))"
          by -(rule path_Main_CondFalse,auto simp:add.assoc)
        moreover
        from path2 obtain ax' asx' where [simp]:"as' = ax'#asx'"
          and "sourcenode ax' = (Main,Entry)" and "valid_edge wfp'' ax'"
          and "wfp''  targetnode ax' -asx'→* (Main, Label l'')"
          by -(erule ProcCFG.path.cases,fastforce+)
        with wf have "targetnode ax' = (Main,Label 0)"
          by(fastforce elim:PCFG.cases dest:Proc_CFG_EntryD Proc_CFG_Call_Labels 
                      simp:valid_edge_def)
        with wfp''  targetnode ax' -asx'→* (Main, Label l'') intra2
        have "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
          ((Main,Label 0),(λcf. state_check cf b (Some false)),
          (Main,Label (#:c1 + 1)))#(asx' ⊕s (#:c1 + 1))→* 
          (Main,Label l''  (#:c1 + 1))"
          apply - apply(rule ProcCFG.path.intros)+ apply(rule path_Main_CondFalse)
          by(auto intro:Main Proc_CFG_Entry Proc_CFG_CondFalse simp:valid_edge_def)
        ultimately show ?thesis using intra1 intra2
          by(fastforce simp:label_incrs_def intra_kind_def add.assoc)
      qed
    qed
  next
    case (While b c')
    note IH = l wfp. l < #:c'; Rep_wf_prog wfp = (c', procs) 
      as as'. wfp  (Main, Label l) -as→* (Main, Exit) 
      (aset as. intra_kind (kind a)) 
      wfp  (Main, Entry) -as'→* (Main, Label l)  (aset as'. intra_kind (kind a))
    note [simp] = Rep_wf_prog wfp = (while (b) c', procs)
    show ?case
    proof(cases "l = 0")
      case True
      hence "wfp  (Main,Label l) - 
        ((Main,Label 0),(λcf. state_check cf b (Some false)),(Main,Label 1))#
        [((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_WhileFalseSkip 
          Proc_CFG_WhileFalse simp:valid_edge_def)
      moreover
      have "while (b) c'  Entry -IEdge (λs. True)p Label 0" by(rule Proc_CFG_Entry)
      with l = 0 have "wfp  (Main,Entry) 
        -[((Main,Entry),(λs. True),(Main,Label 0))]→* (Main,Label l)"
        by(fastforce intro:ProcCFG.path.intros Main 
                     simp:ProcCFG.valid_node_def valid_edge_def)
      ultimately show ?thesis by(fastforce simp:intra_kind_def)
    next
      case False
      hence "1  l" by simp
      thus ?thesis
      proof(cases "l < 2")
        case True
        with 1  l have [simp]:"l = 1" by simp
        have "wfp  (Main,Label l) -[((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
          by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_WhileFalseSkip 
                      simp:valid_edge_def)
        moreover
        have "while (b) c'  Label 0 -IEdge (λcf. state_check cf b (Some false))p 
          Label 1" by(rule Proc_CFG_WhileFalse)
        hence "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
          [((Main,Label 0),(λcf. state_check cf b (Some false)),(Main,Label 1))]→*
          (Main,Label l)"
          by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_Entry 
                       simp:ProcCFG.valid_node_def valid_edge_def)
        ultimately show ?thesis by(fastforce simp:intra_kind_def)
      next
        case False
        with 1  l have "2  l" by simp
        then obtain l' where [simp]:"l = l' + 2" and "l' = l - 2" 
          by(simp del:add_2_eq_Suc')
        from l < #:while (b) c' have "l' < #:c'" by simp
        from Rep_wf_prog wfp = (while (b) c', procs)
        obtain wfp' where [simp]:"Rep_wf_prog wfp' = (c', procs)" 
          by(erule wfp_WhileBody)
        from IH[OF l' < #:c' this] obtain as as' 
          where path1:"wfp'  (Main, Label l') -as→* (Main, Exit)"
          and intra1:"aset as. intra_kind (kind a)"
          and path2:"wfp'  (Main, Entry) -as'→* (Main, Label l')"
          and intra2:"aset as'. intra_kind (kind a)" by blast
        from path1 have "as  []" by(fastforce elim:ProcCFG.path.cases)
        with path1 obtain ax asx where [simp]:"as = asx@[ax]"
          and "wfp'  (Main, Label l') -asx→* sourcenode ax"
          and "valid_edge wfp' ax" and "targetnode ax = (Main, Exit)"
          by -(erule ProcCFG.path_split_snoc,fastforce+)
        with wf obtain lx etx where "sourcenode ax = (Main,Label lx)"
          and "intra_kind (kind ax)"
          apply(auto elim!:PCFG.cases dest:Proc_CFG_Call_Labels simp:valid_edge_def)
          by(case_tac n)(auto dest:Proc_CFG_IEdge_intra_kind)
        with wfp'  (Main, Label l') -asx→* sourcenode ax intra1
        have "wfp  (Main, Label l'  2) -asx ⊕s 2→* (Main,Label lx  2)"
          by -(rule path_Main_WhileBody,auto)
        from valid_edge wfp' ax sourcenode ax = (Main,Label lx)
          targetnode ax = (Main, Exit) intra_kind (kind ax) wf
        have "while (b) c',procs  (Main,Label lx  2) -kind ax 
          (Main,Label 0)"
          by(fastforce intro!:Main Proc_CFG_WhileBodyExit elim!:PCFG.cases 
                        dest:Proc_CFG_Call_Labels simp:valid_edge_def)
        hence "wfp  (Main,Label lx  2) 
          -((Main,Label lx  2),kind ax,(Main,Label 0))#
          ((Main,Label 0),(λcf. state_check cf b (Some false)),(Main,Label 1))#
          [((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
          by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_WhileFalse 
            Proc_CFG_WhileFalseSkip simp:valid_edge_def)
        with wfp  (Main, Label l'  2) -asx ⊕s 2→* (Main,Label lx  2)
        have "wfp  (Main, Label l) -(asx ⊕s 2)@
          (((Main,Label lx  2),kind ax,(Main,Label 0))#
          ((Main,Label 0),(λcf. state_check cf b (Some false)),(Main,Label 1))#
          [((Main,Label 1),id,(Main,Exit))])→* (Main,Exit)"
          by(fastforce intro:ProcCFG.path_Append)
        moreover
        from path2 have "as'  []" by(fastforce elim:ProcCFG.path.cases)
        with path2 obtain ax' asx' where [simp]:"as' = ax'#asx'"
          and "wfp'  targetnode ax' -asx'→* (Main,Label l')"
          and "valid_edge wfp' ax'" and "sourcenode ax' = (Main, Entry)"
          by -(erule ProcCFG.path_split_Cons,fastforce+)
        with wf have "targetnode ax' = (Main,Label 0)" and "intra_kind (kind ax')"
          by(fastforce elim!:PCFG.cases dest:Proc_CFG_Call_Labels 
            Proc_CFG_EntryD simp:intra_kind_def valid_edge_def)+
        with wfp'  targetnode ax' -asx'→* (Main,Label l') intra2
        have "wfp  (Main, Label 0  2) -asx' ⊕s 2→* (Main,Label l'  2)"
          by -(rule path_Main_WhileBody,auto simp del:add_2_eq_Suc')
        hence "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
          ((Main,Label 0),(λcf. state_check cf b (Some true)),(Main,Label 2))#
          (asx' ⊕s 2)→* (Main,Label l)"
          by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_WhileTrue 
            Proc_CFG_Entry simp:valid_edge_def)
        ultimately show ?thesis using intra_kind (kind ax) intra1 intra2
          by(fastforce simp:label_incrs_def intra_kind_def)
      qed
    qed
  next
    case (Call p es rets)
    note Rep [simp] = Rep_wf_prog wfp = (Call p es rets, procs)
    have cC:"containsCall procs (Call p es rets) [] p" by simp
    show ?case
    proof(cases "l = 0")
      case True
      have "wfp  (Main,Label 0) -((Main,Label 0),(λs. False),(Main,Label 1))#
        [((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_CallSkip MainCallReturn
          Proc_CFG_Call simp:valid_edge_def)
      moreover
      have "Call p es rets,procs  (Main,Entry) -(λs. True) (Main,Label 0)"
        by(fastforce intro:Main Proc_CFG_Entry)
      hence "wfp  (Main,Entry) -[((Main,Entry),(λs. True),(Main,Label 0))]→*
        (Main,Label 0)"
        by(fastforce intro:ProcCFG.path.intros 
          simp:ProcCFG.valid_node_def valid_edge_def)
      ultimately show ?thesis using l = 0 by(fastforce simp:intra_kind_def)
    next
      case False
      with l < #:Call p es rets have "l = 1" by simp
      have "wfp  (Main,Label 1) -[((Main,Label 1),id,(Main,Exit))]→* (Main,Exit)"
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_CallSkip
                    simp:valid_edge_def)
      moreover
      have "Call p es rets,procs  (Main,Label 0) -(λs. False) (Main,Label 1)"
        by(fastforce intro:MainCallReturn Proc_CFG_Call)
      hence "wfp  (Main,Entry) -((Main,Entry),(λs. True),(Main,Label 0))#
        [((Main,Label 0),(λs. False),(Main,Label 1))]→* (Main,Label 1)"
        by(fastforce intro:ProcCFG.path.intros Main Proc_CFG_Entry 
                    simp:ProcCFG.valid_node_def valid_edge_def)
      ultimately show ?thesis using l = 1 by(fastforce simp:intra_kind_def)
    qed
  qed
qed



subsection ‹Lifting from edges in procedure Main to arbitrary procedures›

lemma lift_edge_Main_Main:
  "c,procs  (Main, n) -et (Main, n'); (p,ins,outs,c)  set procs;
  containsCall procs prog ps p; well_formed procs 
   prog,procs  (p, n) -et (p, n')"
proof(induct "(Main,n)" et "(Main,n')" rule:PCFG.induct)
  case Main thus ?case by(fastforce intro:Proc)
next
  case MainCallReturn thus ?case by(fastforce intro:ProcCallReturn)
qed auto

lemma lift_edge_Main_Proc:
  "c,procs  (Main, n) -et (q, n'); q  Main; (p,ins,outs,c)  set procs;
  containsCall procs prog ps p; well_formed procs 
   et'. prog,procs  (p, n) -et' (q, n')"
proof(induct "(Main,n)" et "(q,n')" rule:PCFG.induct)
  case (MainCall l esx retsx n'x insx outsx cx)
  from c  Label l -CEdge (q, esx, retsx)p n'x 
  obtain l' where [simp]:"n'x = Label l'" by(fastforce dest:Proc_CFG_Call_Labels)
  with MainCall have "prog,procs  (p, n) 
    -(λs. True):(p,n'x)↪⇘qmap (λe cf. interpret e cf) esx (q, n')"
    by(fastforce intro:ProcCall)
  thus ?case by fastforce
qed auto

lemma lift_edge_Proc_Main:
  "c,procs  (q, n) -et (Main, n'); q  Main; (p,ins,outs,c)  set procs;
  containsCall procs prog ps p; well_formed procs 
   et'. prog,procs  (q, n) -et' (p, n')"
proof(induct "(q,n)" et "(Main,n')" rule:PCFG.induct)
  case (MainReturn l esx retsx l' insx outsx cx)
  note [simp] = Exit = n[THEN sym] Label l' = n'[THEN sym]
  from MainReturn have "prog,procs  (q,Exit) -(λcf. snd cf = (p,Label l'))↩⇘q(λcf cf'. cf'(retsx [:=] map cf outsx)) (p,Label l')"
    by(fastforce intro!:ProcReturn)
  thus ?case by fastforce
qed auto


fun lift_edge :: "edge  pname  edge"
where "lift_edge a p = ((p,snd(sourcenode a)),kind a,(p,snd(targetnode a)))"

fun lift_path :: "edge list  pname  edge list"
  where "lift_path as p = map (λa. lift_edge a p) as"


lemma lift_path_Proc: 
  fixes wfp
  assumes "Rep_wf_prog wfp' = (c,procs)" and "Rep_wf_prog wfp = (prog,procs)"
  and "(p,ins,outs,c)  set procs" and "containsCall procs prog ps p"
  shows "wfp'  (Main,n) -as→* (Main,n'); a  set as. intra_kind (kind a)
   wfp  (p,n) -lift_path as p→* (p,n')"
proof(induct "(Main,n)" as "(Main,n')" arbitrary:n rule:ProcCFG.path.induct)
  case empty_path
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from CFG.valid_node sourcenode targetnode (valid_edge wfp') (Main, n')
    assms wf
  have "CFG.valid_node sourcenode targetnode (valid_edge wfp) (p,n')"
    apply(auto simp:ProcCFG.valid_node_def valid_edge_def)
     apply(case_tac "ab = Main")
      apply(fastforce dest:lift_edge_Main_Main)
     apply(fastforce dest!:lift_edge_Main_Proc)
    apply(case_tac "a = Main")
     apply(fastforce dest:lift_edge_Main_Main)
    by(fastforce dest!:lift_edge_Proc_Main)
  thus ?case by(fastforce dest:ProcCFG.empty_path)
next
  case (Cons_path m'' as a n)
  note IH = n. m'' = (Main, n); aset as. intra_kind (kind a)
     wfp  (p, n) -lift_path as p→* (p, n')
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs" 
    by(fastforce intro:wf_wf_prog)
  from aset (a # as). intra_kind (kind a) have "intra_kind (kind a)"
    and "aset as. intra_kind (kind a)" by simp_all
  from valid_edge wfp' a intra_kind (kind a) sourcenode a = (Main, n) 
    targetnode a = m'' Rep_wf_prog wfp' = (c,procs)
  obtain n'' where "m'' = (Main, n'')"
    by(fastforce elim:PCFG.cases simp:valid_edge_def intra_kind_def)
  with valid_edge wfp' a Rep_wf_prog wfp' = (c,procs)
    sourcenode a = (Main, n) targetnode a = m''
    (p,ins,outs,c)  set procs containsCall procs prog ps p 
    Rep_wf_prog wfp = (prog,procs) wf
  have "prog,procs  (p, n) -kind a (p, n'')"
    by(auto intro:lift_edge_Main_Main simp:valid_edge_def)  
  from IH[OF m'' = (Main, n'') aset as. intra_kind (kind a)]
  have "wfp  (p, n'') -lift_path as p→* (p, n')" .
  with prog,procs  (p, n) -kind a (p, n'') Rep_wf_prog wfp = (prog,procs)
    sourcenode a = (Main, n) targetnode a = m'' m'' = (Main, n'')
  show ?case by simp (rule ProcCFG.Cons_path,auto simp:valid_edge_def)
qed


subsection ‹Existence of paths from Entry and to Exit›

lemma Label_Proc_CFG_Entry_Exit_path_Proc:
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)" and "l < #:c"
  and "(p,ins,outs,c)  set procs" and "containsCall procs prog ps p"
  obtains as as' where "wfp  (p,Label l) -as→* (p,Exit)"
  and "a  set as. intra_kind (kind a)"
  and "wfp  (p,Entry) -as'→* (p,Label l)"
  and "a  set as'. intra_kind (kind a)"
proof(atomize_elim)
  from Rep_wf_prog wfp = (prog,procs) (p,ins,outs,c)  set procs
    containsCall procs prog ps p
  obtain wfp' where "Rep_wf_prog wfp' = (c,procs)" by(erule wfp_Call)
  from this l < #:c obtain as as' where "wfp'  (Main,Label l) -as→* (Main,Exit)"
    and "a  set as. intra_kind (kind a)"
    and "wfp'  (Main,Entry) -as'→* (Main,Label l)"
    and "a  set as'. intra_kind (kind a)" 
    by(erule Label_Proc_CFG_Entry_Exit_path_Main)
  from Rep_wf_prog wfp' = (c,procs) Rep_wf_prog wfp = (prog,procs)
    (p,ins,outs,c)  set procs containsCall procs prog ps p
    wfp'  (Main,Label l) -as→* (Main,Exit) a  set as. intra_kind (kind a)
  have "wfp  (p,Label l) -lift_path as p→* (p,Exit)"
    by(fastforce intro:lift_path_Proc)
  moreover
  from Rep_wf_prog wfp' = (c,procs) Rep_wf_prog wfp = (prog,procs)
    (p,ins,outs,c)  set procs containsCall procs prog ps p
    wfp'  (Main,Entry) -as'→* (Main,Label l) a  set as'. intra_kind (kind a)
  have "wfp  (p,Entry) -lift_path as' p→* (p,Label l)"
    by(fastforce intro:lift_path_Proc)
  moreover
  from a  set as. intra_kind (kind a) a  set as'. intra_kind (kind a)
  have "a  set (lift_path as p). intra_kind (kind a)"
    and "a  set (lift_path as' p). intra_kind (kind a)" by auto
  ultimately
  show "as as'. wfp  (p, Label l) -as→* (p, Exit) 
    (aset as. intra_kind (kind a))  wfp  (p, Entry) -as'→* (p, Label l) 
    (aset as'. intra_kind (kind a))" by fastforce
qed


lemma Entry_to_Entry_and_Exit_to_Exit: 
  fixes wfp
  assumes "Rep_wf_prog wfp = (prog,procs)"
  and "containsCall procs prog ps p" and "(p,ins,outs,c)  set procs"
  obtains as as' where "CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (Main,Entry) as (p,Entry)"
  and "CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (p,Exit) as' (Main,Exit)"
proof(atomize_elim)
  from containsCall procs prog ps p (p,ins,outs,c)  set procs
  show "as as'. CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
    (get_return_edges wfp) (Main, Entry) as (p, Entry) 
    CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
    (get_return_edges wfp) (p, Exit) as' (Main, Exit)"
  proof(induct ps arbitrary:p ins outs c rule:rev_induct)
    case Nil
    from containsCall procs prog [] p
    obtain lx es rets lx' where "prog  Label lx -CEdge (p,es,rets)p Label lx'"
      by(erule containsCall_empty_Proc_CFG_Call_edge)
    with (p, ins, outs, c)  set procs
    have "prog,procs  (Main,Label lx) -(λs. True):(Main,Label lx')↪⇘pmap (λe cf. interpret e cf) es  (p,Entry)" 
      and "prog,procs  (p,Exit) -(λcf. snd cf = (Main,Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (Main,Label lx')"
      by -(rule MainCall,assumption+,rule MainReturn)
    with Rep_wf_prog wfp = (prog,procs)
    have "wfp  (Main,Label lx) -[((Main,Label lx),
      (λs. True):(Main,Label lx')↪⇘pmap (λe cf. interpret e cf) es,(p,Entry))]→* 
      (p,Entry)"
      and "wfp  (p,Exit) -[((p,Exit),(λcf. snd cf = (Main,Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)),(Main,Label lx'))]→* (Main,Label lx')"
      by(fastforce intro:ProcCFG.path.intros 
        simp:ProcCFG.valid_node_def valid_edge_def)+
    moreover
    from prog  Label lx -CEdge (p,es,rets)p Label lx'
    have "lx < #:prog" and "lx' < #:prog"
      by(auto intro:Proc_CFG_sourcelabel_less_num_nodes 
                    Proc_CFG_targetlabel_less_num_nodes)
    from Rep_wf_prog wfp = (prog,procs) lx < #:prog obtain as 
      where "wfp  (Main,Entry) -as→* (Main,Label lx)"
      and "a  set as. intra_kind (kind a)"
      by -(erule Label_Proc_CFG_Entry_Exit_path_Main)
    moreover
    from Rep_wf_prog wfp = (prog,procs) lx' < #:prog obtain as' 
      where "wfp  (Main,Label lx') -as'→* (Main,Exit)"
      and "a  set as'. intra_kind (kind a)"
      by -(erule Label_Proc_CFG_Entry_Exit_path_Main)
    moreover
    from a  set as. intra_kind (kind a) 
    have "CFG.valid_path kind (get_return_edges wfp) 
      (as@[((Main,Label lx),(λs. True):(Main,Label lx')↪⇘pmap (λe cf. interpret e cf) es,(p,Entry))])"
      by(fastforce intro:ProcCFG.same_level_path_valid_path_Append 
        ProcCFG.intras_same_level_path simp:ProcCFG.valid_path_def)
    moreover
    from a  set as'. intra_kind (kind a) 
    have "CFG.valid_path kind (get_return_edges wfp) 
      ([((p,Exit),(λcf. snd cf = (Main,Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)),(Main,Label lx'))]@as')"
      by(fastforce intro:ProcCFG.valid_path_same_level_path_Append 
        ProcCFG.intras_same_level_path simp:ProcCFG.valid_path_def)
    ultimately show ?case by(fastforce intro:ProcCFG.path_Append simp:ProcCFG.vp_def)
  next
    case (snoc p' ps')
    note IH = p ins outs c. 
      containsCall procs prog ps' p; (p,ins,outs,c)  set procs
       as as'. CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) (Main, Entry) as (p, Entry) 
      CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) (p, Exit) as' (Main, Exit)
    from containsCall procs prog (ps' @ [p']) p
    obtain ins' outs' c' where "(p',ins',outs',c')  set procs"
      and "containsCall procs c' [] p" 
      and "containsCall procs prog ps' p'" by(auto elim:containsCallE)
    from IH[OF containsCall procs prog ps' p' (p',ins',outs',c')  set procs] 
    obtain as as' where pathE:"CFG.valid_path' sourcenode targetnode kind 
      (valid_edge wfp) (get_return_edges wfp) (Main, Entry) as (p', Entry)"
      and pathX:"CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) (p', Exit) as' (Main, Exit)" by blast
    from containsCall procs c' [] p
    obtain lx es rets lx' where edge:"c'  Label lx -CEdge (p,es,rets)p Label lx'"
      by(erule containsCall_empty_Proc_CFG_Call_edge)
    hence "lx < #:c'" and "lx' < #:c'"
      by(auto intro:Proc_CFG_sourcelabel_less_num_nodes 
                    Proc_CFG_targetlabel_less_num_nodes)
    from lx < #:c' Rep_wf_prog wfp = (prog,procs) (p',ins',outs',c')  set procs
      containsCall procs prog ps' p' obtain asx 
      where "wfp  (p',Entry) -asx→* (p',Label lx)"
      and "a  set asx. intra_kind (kind a)"
      by(fastforce elim:Label_Proc_CFG_Entry_Exit_path_Proc)
    with pathE have pathE2:"CFG.valid_path' sourcenode targetnode kind 
      (valid_edge wfp) (get_return_edges wfp) (Main, Entry) (as@asx) (p', Label lx)"
      by(fastforce intro:ProcCFG.path_Append ProcCFG.valid_path_same_level_path_Append
        ProcCFG.intras_same_level_path simp:ProcCFG.vp_def)
    from lx' < #:c' Rep_wf_prog wfp = (prog,procs)
      (p',ins',outs',c')  set procs containsCall procs prog ps' p' 
    obtain asx' where "wfp  (p',Label lx') -asx'→* (p',Exit)"
      and "a  set asx'. intra_kind (kind a)"
      by(fastforce elim:Label_Proc_CFG_Entry_Exit_path_Proc)
    with pathX have pathX2:"CFG.valid_path' sourcenode targetnode kind 
      (valid_edge wfp) (get_return_edges wfp) (p', Label lx') (asx'@as') (Main, Exit)"
      by(fastforce intro:ProcCFG.path_Append ProcCFG.same_level_path_valid_path_Append
        ProcCFG.intras_same_level_path simp:ProcCFG.vp_def)
    from edge (p,ins,outs,c)  set procs (p',ins',outs',c')  set procs
      containsCall procs prog ps' p'
    have "prog,procs  (p',Label lx) -(λs. True):(p',Label lx')↪⇘pmap (λe cf. interpret e cf) es (p,Entry)"
      and "prog,procs  (p,Exit) -(λcf. snd cf = (p',Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)) (p',Label lx')"
      by(fastforce intro:ProcCall ProcReturn)+
    with Rep_wf_prog wfp = (prog,procs)
    have path:"wfp  (p',Label lx) -[((p',Label lx),(λs. True):(p',Label lx')↪⇘pmap (λe cf. interpret e cf) es,(p,Entry))]→* (p,Entry)"
      and path':"wfp  (p,Exit) -[((p,Exit),(λcf. snd cf = (p',Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)),(p',Label lx'))]→* 
      (p',Label lx')"
      by(fastforce intro:ProcCFG.path.intros 
                  simp:ProcCFG.valid_node_def valid_edge_def)+
    from path pathE2 have "CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) (Main, Entry) ((as@asx)@[((p',Label lx),
      (λs. True):(p',Label lx')↪⇘pmap (λe cf. interpret e cf) es,(p,Entry))])
      (p,Entry)"
      apply(unfold ProcCFG.vp_def) apply(rule conjI)
       apply(fastforce intro:ProcCFG.path_Append)
      by(unfold ProcCFG.valid_path_def,fastforce intro:ProcCFG.vpa_snoc_Call)
    moreover
    from path' pathX2 have "CFG.valid_path' sourcenode targetnode kind 
      (valid_edge wfp) (get_return_edges wfp) (p,Exit)
      ([((p,Exit),(λcf. snd cf = (p',Label lx'))↩⇘p(λcf cf'. cf'(rets [:=] map cf outs)),(p',Label lx'))]@(asx'@as')) (Main, Exit)"
      apply(unfold ProcCFG.vp_def) apply(rule conjI)
       apply(fastforce intro:ProcCFG.path_Append)
      by(simp add:ProcCFG.valid_path_def ProcCFG.valid_path_def)
    ultimately show ?case by blast
  qed
qed


lemma edge_valid_paths:
  fixes wfp
  assumes "prog,procs  sourcenode a -kind a targetnode a"
  and disj:"(p,n) = sourcenode a  (p,n) = targetnode a" 
  and [simp]:"Rep_wf_prog wfp = (prog,procs)"
  shows "as as'. CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
                (get_return_edges wfp) (Main,Entry) as (p,n) 
              CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
                (get_return_edges wfp) (p,n) as' (Main,Exit)"
proof -
  from Rep_wf_prog wfp = (prog,procs) have wf:"well_formed procs"
    by(fastforce intro:wf_wf_prog)
  from prog,procs  sourcenode a -kind a targetnode a
  show ?thesis
  proof(induct "sourcenode a" "kind a" "targetnode a" rule:PCFG.induct)
    case (Main nx nx')
    from (Main, nx) = sourcenode a[THEN sym] (Main, nx') = targetnode a[THEN sym]
      disj have [simp]:"p = Main" by auto
    have "prog,procs  (Main, Entry) -(λs. False) (Main, Exit)"
      by(fastforce intro:PCFG.Main Proc_CFG_Entry_Exit)
    hence EXpath:"wfp  (Main,Entry) -[((Main,Entry),(λs. False),(Main,Exit))]→*
        (Main,Exit)"
      by(fastforce intro:ProcCFG.path.intros
        simp:valid_edge_def ProcCFG.valid_node_def)
    show ?case
    proof(cases n)
      case (Label l)
      with prog  nx -IEdge (kind a)p nx' (Main, nx) = sourcenode a[THEN sym]
        (Main, nx') = targetnode a[THEN sym] disj
      have "l < #:prog" by(auto intro:Proc_CFG_sourcelabel_less_num_nodes
        Proc_CFG_targetlabel_less_num_nodes)
      with Rep_wf_prog wfp = (prog,procs) 
      obtain as as' where "wfp  (Main,Entry) -as→* (Main,Label l)"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (Main,Label l) -as'→* (Main,Exit)"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Main)+
      with Label show ?thesis
        apply(rule_tac x="as" in exI) apply(rule_tac x="as'" in exI) apply simp
        by(fastforce intro:ProcCFG.intra_path_vp simp:ProcCFG.intra_path_def)
    next
      case Entry
      hence "wfp  (Main,Entry) -[]→* (Main,n)" by(fastforce intro:ProcCFG.empty_path)
      with EXpath show ?thesis by(fastforce simp:ProcCFG.vp_def ProcCFG.valid_path_def)
    next
      case Exit
      hence "wfp  (Main,n) -[]→* (Main,Exit)" by(fastforce intro:ProcCFG.empty_path)
      with Exit EXpath show ?thesis using Exit
        apply(rule_tac x="[((Main,Entry),(λs. False),(Main,Exit))]" in exI) 
        apply simp
        by(fastforce intro:ProcCFG.intra_path_vp 
          simp:ProcCFG.intra_path_def intra_kind_def)
    qed
  next
    case (Proc px ins outs c nx nx' ps)
    from (px, ins, outs, c)  set procs wf have [simp]:"px  Main" by auto
    from disj (px, nx) = sourcenode a[THEN sym] (px, nx') = targetnode a[THEN sym]
    have [simp]:"p = px" by auto
    from Rep_wf_prog wfp = (prog,procs) 
      containsCall procs prog ps px (px, ins, outs, c)  set procs
    obtain asx asx' where path:"CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (Main,Entry) asx (px,Entry)"
      and path':"CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (px,Exit) asx' (Main,Exit)"
      by -(erule Entry_to_Entry_and_Exit_to_Exit)+
    from containsCall procs prog ps px (px, ins, outs, c)  set procs
    have "prog,procs  (px, Entry) -(λs. False) (px, Exit)"
      by(fastforce intro:PCFG.Proc Proc_CFG_Entry_Exit)
    hence EXpath:"wfp  (px,Entry) -[((px,Entry),(λs. False),(px,Exit))]→* 
      (px,Exit)" by(fastforce intro:ProcCFG.path.intros 
        simp:valid_edge_def ProcCFG.valid_node_def)
    show ?case
    proof(cases n)
      case (Label l)
      with c  nx -IEdge (kind a)p nx' disj (px, nx) = sourcenode a[THEN sym]
        (px, nx') = targetnode a[THEN sym]
      have "l < #:c" by(auto intro:Proc_CFG_sourcelabel_less_num_nodes
        Proc_CFG_targetlabel_less_num_nodes)
      with Rep_wf_prog wfp = (prog,procs) (px, ins, outs, c)  set procs 
        containsCall procs prog ps px
      obtain as as' where "wfp  (px,Entry) -as→* (px,Label l)"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (px,Label l) -as'→* (px,Exit)"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Proc)+
      with path path' show ?thesis using Label
        apply(rule_tac x="asx@as" in exI) apply(rule_tac x="as'@asx'" in exI)
        by(auto intro:ProcCFG.path_Append ProcCFG.valid_path_same_level_path_Append
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:ProcCFG.vp_def)
    next
      case Entry
      from EXpath path' have "CFG.valid_path' sourcenode targetnode kind 
        (valid_edge wfp) (get_return_edges wfp) (px,Entry) 
        ([((px,Entry),(λs. False),(px,Exit))]@asx') (Main, Exit)"
        apply(unfold ProcCFG.vp_def) apply(erule conjE) apply(rule conjI)
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:intra_kind_def)+
      with path Entry show ?thesis by simp blast
    next
      case Exit
      with path EXpath path' show ?thesis
        apply(rule_tac x="asx@[((px,Entry),(λs. False),(px,Exit))]" in exI)
        apply simp
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.valid_path_same_level_path_Append ProcCFG.intras_same_level_path
          simp:ProcCFG.vp_def ProcCFG.intra_path_def intra_kind_def)
    qed
  next
    case (MainCall l px es rets nx' ins outs c)
    from disj show ?case
    proof
      assume "(p,n) = sourcenode a"
      with (Main, Label l) = sourcenode a[THEN sym] 
      have [simp]:"n = Label l" "p = Main" by simp_all
      with prog  Label l -CEdge (px, es, rets)p nx' have "l < #:prog"
        by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
      with Rep_wf_prog wfp = (prog,procs) 
      obtain as as' where "wfp  (Main,Entry) -as→* (Main,Label l)"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (Main,Label l) -as'→* (Main,Exit)"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Main)+
      thus ?thesis 
        by(fastforce intro:ProcCFG.intra_path_vp simp:ProcCFG.intra_path_def)
    next
      assume "(p,n) = targetnode a"
      with (px, Entry) = targetnode a[THEN sym] 
      have [simp]:"n = Entry" "p = px" by simp_all
      from prog  Label l -CEdge (px, es, rets)p nx'
      have "containsCall procs prog [] px" 
        by(rule Proc_CFG_Call_containsCall)
      with Rep_wf_prog wfp = (prog,procs) (px, ins, outs, c)  set procs
      obtain as' where Xpath:"CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (px,Exit) as' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)      
      from containsCall procs prog [] px (px, ins, outs, c)  set procs
      have "prog,procs  (px, Entry) -(λs. False) (px, Exit)"
        by(fastforce intro:PCFG.Proc Proc_CFG_Entry_Exit)
      hence "wfp  (px,Entry) -[((px,Entry),(λs. False),(px,Exit))]→* (px,Exit)"
        by(fastforce intro:ProcCFG.path.intros 
          simp:valid_edge_def ProcCFG.valid_node_def)
      with Xpath have "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (px,Entry) 
        ([((px,Entry),(λs. False),(px,Exit))]@as') (Main,Exit)"
        apply(unfold ProcCFG.vp_def) apply(erule conjE) apply(rule conjI)
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:intra_kind_def)+
      with containsCall procs prog [] px Rep_wf_prog wfp = (prog,procs)
        (px, ins, outs, c)  set procs
      show ?thesis by(fastforce elim:Entry_to_Entry_and_Exit_to_Exit)
    qed
  next
    case (ProcCall px ins outs c l p' es' rets' l' ins' outs' c' ps)
    from disj show ?case
    proof
      assume "(p,n) = sourcenode a"
      with (px, Label l) = sourcenode a[THEN sym] 
      have [simp]:"n = Label l" "p = px" by simp_all
      with c  Label l -CEdge (p', es', rets')p Label l' have "l < #:c"
        by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
      from Rep_wf_prog wfp = (prog,procs) l < #:c 
        containsCall procs prog ps px (px, ins, outs, c)  set procs
      obtain as as' where "wfp  (px,Label l) -as→* (px,Exit)"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (px,Entry) -as'→* (px,Label l)"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Proc)+
      moreover
      from Rep_wf_prog wfp = (prog,procs) containsCall procs prog ps px
        (px, ins, outs, c)  set procs obtain asx asx' 
        where" CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (Main,Entry) asx (px,Entry)"
        and "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (px,Exit) asx' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)+
      ultimately show ?thesis 
        apply(rule_tac x="asx@as'" in exI) apply(rule_tac x="as@asx'" in exI)
        by(auto intro:ProcCFG.path_Append ProcCFG.valid_path_same_level_path_Append
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:ProcCFG.vp_def)
    next
      assume "(p,n) = targetnode a"
      with (p', Entry) = targetnode a[THEN sym] 
      have [simp]:"n = Entry" "p = p'" by simp_all
      from c  Label l -CEdge (p', es', rets')p Label l'
      have "containsCall procs c [] p'" by(rule Proc_CFG_Call_containsCall)
      with containsCall procs prog ps px (px, ins, outs, c)  set procs
      have "containsCall procs prog (ps@[px]) p'"
        by(rule containsCall_in_proc)
      with (p', ins', outs', c')  set procs
      have "prog,procs  (p', Entry) -(λs. False) (p', Exit)"
        by(fastforce intro:PCFG.Proc Proc_CFG_Entry_Exit)
      hence "wfp  (p',Entry) -[((p',Entry),(λs. False),(p',Exit))]→* (p',Exit)"
        by(fastforce intro:ProcCFG.path.intros 
          simp:valid_edge_def ProcCFG.valid_node_def)
      moreover
      from Rep_wf_prog wfp = (prog,procs) (p', ins', outs', c')  set procs
        containsCall procs prog (ps@[px]) p'
      obtain as as' where "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (Main,Entry) as (p',Entry)"
        and "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (p',Exit) as' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)+
      ultimately show ?thesis
        apply(rule_tac x="as" in exI)
        apply(rule_tac x="[((p',Entry),(λs. False),(p',Exit))]@as'" in exI)
        apply(unfold ProcCFG.vp_def)
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:intra_kind_def)+
    qed
  next
    case (MainReturn l px es rets l' ins outs c)
    from disj show ?case
    proof
      assume "(p,n) = sourcenode a"
      with (px, Exit) = sourcenode a[THEN sym] 
      have [simp]:"n = Exit" "p = px" by simp_all
      from prog  Label l -CEdge (px, es, rets)p Label l'
      have "containsCall procs prog [] px" by(rule Proc_CFG_Call_containsCall)
      with (px, ins, outs, c)  set procs
      have "prog,procs  (px, Entry) -(λs. False) (px, Exit)"
        by(fastforce intro:PCFG.Proc Proc_CFG_Entry_Exit)
      hence "wfp  (px,Entry) -[((px,Entry),(λs. False),(px,Exit))]→* (px,Exit)"
        by(fastforce intro:ProcCFG.path.intros 
          simp:valid_edge_def ProcCFG.valid_node_def)
      moreover
      from Rep_wf_prog wfp = (prog,procs) (px, ins, outs, c)  set procs
        containsCall procs prog [] px
      obtain as as' where "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (Main,Entry) as (px,Entry)"
        and "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (px,Exit) as' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)+
      ultimately show ?thesis
        apply(rule_tac x="as@[((px,Entry),(λs. False),(px,Exit))]" in exI)
        apply(rule_tac x="as'" in exI)
        apply(unfold ProcCFG.vp_def)
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.valid_path_same_level_path_Append ProcCFG.intras_same_level_path
          simp:intra_kind_def)+
    next
      assume "(p, n) = targetnode a"
      with (Main, Label l') = targetnode a[THEN sym] 
      have [simp]:"n = Label l'" "p = Main" by simp_all
      with prog  Label l -CEdge (px, es, rets)p Label l' have "l' < #:prog"
        by(fastforce intro:Proc_CFG_targetlabel_less_num_nodes)
      with Rep_wf_prog wfp = (prog,procs) 
      obtain as as' where "wfp  (Main,Entry) -as→* (Main,Label l')"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (Main,Label l') -as'→* (Main,Exit)"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Main)+
      thus ?thesis 
        by(fastforce intro:ProcCFG.intra_path_vp simp:ProcCFG.intra_path_def)
    qed
  next
    case (ProcReturn px ins outs c l p' es' rets' l' ins' outs' c' ps)
    from disj show ?case
    proof
      assume "(p,n) = sourcenode a"
      with (p', Exit) = sourcenode a[THEN sym] 
      have [simp]:"n = Exit" "p = p'" by simp_all
      from c  Label l -CEdge (p', es', rets')p Label l'
      have "containsCall procs c [] p'" by(rule Proc_CFG_Call_containsCall)
      with containsCall procs prog ps px (px, ins, outs, c)  set procs
      have "containsCall procs prog (ps@[px]) p'"
        by(rule containsCall_in_proc)
      with (p', ins', outs', c')  set procs
      have "prog,procs  (p', Entry) -(λs. False) (p', Exit)"
        by(fastforce intro:PCFG.Proc Proc_CFG_Entry_Exit)
      hence "wfp  (p',Entry) -[((p',Entry),(λs. False),(p',Exit))]→* (p',Exit)"
        by(fastforce intro:ProcCFG.path.intros 
          simp:valid_edge_def ProcCFG.valid_node_def)
      moreover
      from Rep_wf_prog wfp = (prog,procs) (p', ins', outs', c')  set procs
        containsCall procs prog (ps@[px]) p'
      obtain as as' where "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (Main,Entry) as (p',Entry)"
        and "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (p',Exit) as' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)+
      ultimately show ?thesis
        apply(rule_tac x="as@[((p',Entry),(λs. False),(p',Exit))]" in exI)
        apply(rule_tac x="as'" in exI)
        apply(unfold ProcCFG.vp_def)
        by(fastforce intro:ProcCFG.path_Append 
          ProcCFG.valid_path_same_level_path_Append ProcCFG.intras_same_level_path
          simp:intra_kind_def)+
    next
      assume "(p, n) = targetnode a"
      with (px, Label l') = targetnode a[THEN sym] 
      have [simp]:"n = Label l'" "p = px" by simp_all
      with c  Label l -CEdge (p', es', rets')p Label l' have "l' < #:c"
        by(fastforce intro:Proc_CFG_targetlabel_less_num_nodes)
      from Rep_wf_prog wfp = (prog,procs) l' < #:c 
        containsCall procs prog ps px (px, ins, outs, c)  set procs
      obtain as as' where "wfp  (px,Label l') -as→* (px,Exit)"
        and "a  set as. intra_kind (kind a)"
        and "wfp  (px,Entry) -as'→* (px,Label l')"
        and "a  set as'. intra_kind (kind a)"
        by -(erule Label_Proc_CFG_Entry_Exit_path_Proc)+
      moreover
      from Rep_wf_prog wfp = (prog,procs) containsCall procs prog ps px
        (px, ins, outs, c)  set procs obtain asx asx' 
        where" CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (Main,Entry) asx (px,Entry)"
        and "CFG.valid_path' sourcenode targetnode kind
        (valid_edge wfp) (get_return_edges wfp) (px,Exit) asx' (Main,Exit)"
        by -(erule Entry_to_Entry_and_Exit_to_Exit)+
      ultimately show ?thesis 
        apply(rule_tac x="asx@as'" in exI) apply(rule_tac x="as@asx'" in exI)
        by(auto intro:ProcCFG.path_Append ProcCFG.valid_path_same_level_path_Append
          ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
          simp:ProcCFG.vp_def)
    qed
  next
    case (MainCallReturn nx px es rets nx')
    from prog  nx -CEdge (px, es, rets)p nx' disj
      (Main, nx) = sourcenode a[THEN sym] (Main, nx') = targetnode a[THEN sym]
    obtain l where [simp]:"n = Label l" "p = Main"
      by(fastforce dest:Proc_CFG_Call_Labels)
    from prog  nx -CEdge (px, es, rets)p nx' disj
      (Main, nx) = sourcenode a[THEN sym] (Main, nx') = targetnode a[THEN sym]
    have "l < #:prog" by(auto intro:Proc_CFG_sourcelabel_less_num_nodes
      Proc_CFG_targetlabel_less_num_nodes)
    with Rep_wf_prog wfp = (prog,procs) 
    obtain as as' where "wfp  (Main,Entry) -as→* (Main,Label l)"
      and "a  set as. intra_kind (kind a)"
      and "wfp  (Main,Label l) -as'→* (Main,Exit)"
      and "a  set as'. intra_kind (kind a)"
      by -(erule Label_Proc_CFG_Entry_Exit_path_Main)+
    thus ?thesis
      apply(rule_tac x="as" in exI) apply(rule_tac x="as'" in exI) apply simp
      by(fastforce intro:ProcCFG.intra_path_vp simp:ProcCFG.intra_path_def)
  next
    case (ProcCallReturn px ins outs c nx p' es' rets' nx' ps)
    from (px, ins, outs, c)  set procs wf have [simp]:"px  Main" by auto
    from c  nx -CEdge (p', es', rets')p nx' disj 
      (px, nx) = sourcenode a[THEN sym] (px, nx') = targetnode a[THEN sym]
    obtain l where [simp]:"n = Label l" "p = px"
      by(fastforce dest:Proc_CFG_Call_Labels)
    from c  nx -CEdge (p', es', rets')p nx' disj 
    (px, nx) = sourcenode a[THEN sym] (px, nx') = targetnode a[THEN sym]
    have "l < #:c"
      by(auto intro:Proc_CFG_sourcelabel_less_num_nodes
        Proc_CFG_targetlabel_less_num_nodes)
    with Rep_wf_prog wfp = (prog,procs) (px, ins, outs, c)  set procs 
      containsCall procs prog ps px
    obtain as as' where "wfp  (px,Entry) -as→* (px,Label l)"
      and "a  set as. intra_kind (kind a)"
      and "wfp  (px,Label l) -as'→* (px,Exit)"
      and "a  set as'. intra_kind (kind a)"
      by -(erule Label_Proc_CFG_Entry_Exit_path_Proc)+
    moreover
    from Rep_wf_prog wfp = (prog,procs) 
      containsCall procs prog ps px (px, ins, outs, c)  set procs
    obtain asx asx' where "CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (Main,Entry) asx (px,Entry)"
      and "CFG.valid_path' sourcenode targetnode kind
      (valid_edge wfp) (get_return_edges wfp) (px,Exit) asx' (Main,Exit)"
      by -(erule Entry_to_Entry_and_Exit_to_Exit)+
    ultimately show ?thesis
      apply(rule_tac x="asx@as" in exI) apply(rule_tac x="as'@asx'" in exI)
      by(auto intro:ProcCFG.path_Append ProcCFG.valid_path_same_level_path_Append
        ProcCFG.same_level_path_valid_path_Append ProcCFG.intras_same_level_path
        simp:ProcCFG.vp_def)
  qed
qed



subsection ‹Instantiating the Postdomination› locale›

interpretation ProcPostdomination:
  Postdomination sourcenode targetnode kind "valid_edge wfp" "(Main,Entry)"
  get_proc "get_return_edges wfp" "lift_procs wfp" Main "(Main,Exit)"
  for wfp
proof -
  from Rep_wf_prog[of wfp]
  obtain prog procs where [simp]:"Rep_wf_prog wfp = (prog,procs)" 
    by(fastforce simp:wf_prog_def)
  hence wf:"well_formed procs" by(fastforce intro:wf_wf_prog)
  show "Postdomination sourcenode targetnode kind (valid_edge wfp)
    (Main, Entry) get_proc (get_return_edges wfp) (lift_procs wfp) Main (Main, Exit)"
  proof
    fix m
    assume "CFG.valid_node sourcenode targetnode (valid_edge wfp) m"
    then obtain a where "valid_edge wfp a"
      and "m = sourcenode a  m = targetnode a"
      by(fastforce simp:ProcCFG.valid_node_def)
    obtain p n where [simp]:"m = (p,n)" by(cases m) auto
    from valid_edge wfp a m = sourcenode a  m = targetnode a 
      Rep_wf_prog wfp = (prog,procs)
    show "as. CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) (Main, Entry) as m"
      by(auto dest!:edge_valid_paths simp:valid_edge_def)
  next
    fix m
    assume "CFG.valid_node sourcenode targetnode (valid_edge wfp) m"
    then obtain a where "valid_edge wfp a"
      and "m = sourcenode a  m = targetnode a"
      by(fastforce simp:ProcCFG.valid_node_def)
    obtain p n where [simp]:"m = (p,n)" by(cases m) auto
    from valid_edge wfp a m = sourcenode a  m = targetnode a 
      Rep_wf_prog wfp = (prog,procs)
    show "as. CFG.valid_path' sourcenode targetnode kind (valid_edge wfp)
      (get_return_edges wfp) m as (Main,Exit)"
      by(auto dest!:edge_valid_paths simp:valid_edge_def)
  next
    fix n n'
    assume mex1:"CFGExit.method_exit sourcenode kind (valid_edge wfp) (Main,Exit) n"
      and mex2:"CFGExit.method_exit sourcenode kind (valid_edge wfp) (Main,Exit) n'"
      and "get_proc n = get_proc n'"
    from mex1 
    have "n = (Main,Exit)  (a Q p f. n = sourcenode a  valid_edge wfp a  
      kind a = Q↩⇘pf)" by(simp add:ProcCFGExit.method_exit_def)
    thus "n = n'"
    proof
      assume "n = (Main,Exit)"
      from mex2 have "n' = (Main,Exit)  (a Q p f. n' = sourcenode a  
        valid_edge wfp a  kind a = Q↩⇘pf)" 
        by(simp add:ProcCFGExit.method_exit_def)
      thus ?thesis
      proof
        assume "n' = (Main,Exit)"
        with n = (Main,Exit) show ?thesis by simp
      next
        assume "a Q p f. n' = sourcenode a  
          valid_edge wfp a  kind a = Q↩⇘pf"
        then obtain a Q p f where "n' = sourcenode a"
          and "valid_edge wfp a" and "kind a = Q↩⇘pf" by blast
        from valid_edge wfp a kind a = Q↩⇘pf
        have "get_proc (sourcenode a) = p" by(rule ProcCFG.get_proc_return)
        with get_proc n = get_proc n' n = (Main,Exit) n' = sourcenode a
        have "get_proc (Main,Exit) = p" by simp
        hence "p = Main" by simp
        with kind a = Q↩⇘pf have "kind a = Q↩⇘Mainf" by simp
        with valid_edge wfp a have False by(rule ProcCFG.Main_no_return_source)
        thus ?thesis by simp
      qed
    next
      assume "a Q p f. n = sourcenode a  
        valid_edge wfp a  kind a = Q↩⇘pf"
      then obtain a Q p f where "n = sourcenode a"
        and "valid_edge wfp a" and "kind a = Q↩⇘pf" by blast
      from valid_edge wfp a kind a = Q↩⇘pf
      have "get_proc (sourcenode a) = p" by(rule ProcCFG.get_proc_return)
      from mex2 have "n' = (Main,Exit)  (a Q p f. n' = sourcenode a  
        valid_edge wfp a  kind a = Q↩⇘pf)" 
        by(simp add:ProcCFGExit.method_exit_def)
      thus ?thesis
      proof
        assume "n' = (Main,Exit)"
        from get_proc (sourcenode a) = p get_proc n = get_proc n'
          n' = (Main,Exit) n = sourcenode a
        have "get_proc (Main,Exit) = p" by simp
        hence "p = Main" by simp
        with kind a = Q↩⇘pf have "kind a = Q↩⇘Mainf" by simp
        with valid_edge wfp a have False by(rule ProcCFG.Main_no_return_source)
        thus ?thesis by simp
      next
        assume "a Q p f. n' = sourcenode a  
          valid_edge wfp a  kind a = Q↩⇘pf"
        then obtain a' Q' p' f' where "n' = sourcenode a'"
          and "valid_edge wfp a'" and "kind a' = Q'↩⇘p'f'" by blast
        from valid_edge wfp a' kind a' = Q'↩⇘p'f'
        have "get_proc (sourcenode a') = p'" by(rule ProcCFG.get_proc_return)
        with get_proc n = get_proc n' get_proc (sourcenode a) = p
          n = sourcenode a n' = sourcenode a'
        have "p' = p" by simp
        from valid_edge wfp a kind a = Q↩⇘pf
        have "sourcenode a = (p,Exit)" by(auto elim:PCFG.cases simp:valid_edge_def)
        from valid_edge wfp a' kind a' = Q'↩⇘p'f'
        have "sourcenode a' = (p',Exit)" by(auto elim:PCFG.cases simp:valid_edge_def)
        with n = sourcenode a n' = sourcenode a' p' = p
          sourcenode a = (p,Exit) show ?thesis by simp
      qed
    qed
  qed
qed


end