Theory LiftingInter

section ‹Framework Graph Lifting for Noninterference›

theory LiftingInter 
imports NonInterferenceInter 
begin

text ‹In this section, we show how a valid CFG from the slicing framework in
cite"Wasserrab:08" can be lifted to fulfil all properties of the 
NonInterferenceIntraGraph› locale. Basically, we redefine the
hitherto existing Entry› and Exit› nodes as new
High› and Low› nodes, and introduce two new nodes
NewEntry› and NewExit›. Then, we have to lift all functions
to operate on this new graph.›

subsection ‹Liftings›

subsubsection ‹The datatypes›

datatype 'node LDCFG_node = Node 'node
  | NewEntry
  | NewExit


type_synonym ('edge,'node,'var,'val,'ret,'pname) LDCFG_edge = 
  "'node LDCFG_node × (('var,'val,'ret,'pname) edge_kind) × 'node LDCFG_node"


subsubsection ‹Lifting basic definitions using @{typ 'edge} and @{typ 'node}

inductive lift_valid_edge :: "('edge  bool)  ('edge  'node)  ('edge  'node) 
  ('edge  ('var,'val,'ret,'pname) edge_kind)  'node  'node  
  ('edge,'node,'var,'val,'ret,'pname) LDCFG_edge  
  bool"
for valid_edge::"'edge  bool" and src::"'edge  'node" and trg::"'edge  'node" 
  and knd::"'edge  ('var,'val,'ret,'pname) edge_kind" and E::'node and X::'node

where lve_edge:
  "valid_edge a; src a  E  trg a  X; 
    e = (Node (src a),knd a,Node (trg a))
   lift_valid_edge valid_edge src trg knd E X e"

  | lve_Entry_edge:
  "e = (NewEntry,(λs. True),Node E) 
   lift_valid_edge valid_edge src trg knd E X e"

  | lve_Exit_edge:
  "e = (Node X,(λs. True),NewExit) 
   lift_valid_edge valid_edge src trg knd E X e"

  | lve_Entry_Exit_edge:
  "e = (NewEntry,(λs. False),NewExit) 
   lift_valid_edge valid_edge src trg knd E X e"


lemma [simp]:"¬ lift_valid_edge valid_edge src trg knd E X (Node E,et,Node X)"
by(auto elim:lift_valid_edge.cases)



fun lift_get_proc :: "('node  'pname)  'pname  'node LDCFG_node  'pname"
  where "lift_get_proc get_proc Main (Node n) = get_proc n"
  | "lift_get_proc get_proc Main NewEntry = Main"
  | "lift_get_proc get_proc Main NewExit = Main"


inductive_set lift_get_return_edges :: "('edge  'edge set)  ('edge  bool)  
  ('edge  'node)  ('edge  'node)  ('edge  ('var,'val,'ret,'pname) edge_kind) 
   ('edge,'node,'var,'val,'ret,'pname) LDCFG_edge 
   ('edge,'node,'var,'val,'ret,'pname) LDCFG_edge set"
for get_return_edges :: "'edge  'edge set" and valid_edge :: "'edge  bool"
  and src::"'edge  'node" and trg::"'edge  'node" 
  and knd::"'edge  ('var,'val,'ret,'pname) edge_kind" 
  and e::"('edge,'node,'var,'val,'ret,'pname) LDCFG_edge"
where lift_get_return_edgesI:
  "e = (Node (src a),knd a,Node (trg a)); valid_edge a; a'  get_return_edges a; 
  e' = (Node (src a'),knd a',Node (trg a'))
   e'  lift_get_return_edges get_return_edges valid_edge src trg knd e"


subsubsection ‹Lifting the Def and Use sets›

inductive_set lift_Def_set :: "('node  'var set)  'node  'node  
                       'var set  'var set  ('node LDCFG_node × 'var) set"
for Def::"('node  'var set)" and E::'node and X::'node 
  and H::"'var set" and L::"'var set"

where lift_Def_node: 
  "V  Def n  (Node n,V)  lift_Def_set Def E X H L"

  | lift_Def_High:
  "V  H  (Node E,V)  lift_Def_set Def E X H L"

abbreviation lift_Def :: "('node  'var set)  'node  'node  
                       'var set  'var set  'node LDCFG_node  'var set"
  where "lift_Def Def E X H L n  {V. (n,V)  lift_Def_set Def E X H L}"


inductive_set lift_Use_set :: "('node  'var set)  'node  'node  
                       'var set  'var set  ('node LDCFG_node × 'var) set"
for Use::"'node  'var set" and E::'node and X::'node 
  and H::"'var set" and L::"'var set"

where 
  lift_Use_node: 
  "V  Use n  (Node n,V)  lift_Use_set Use E X H L"

  | lift_Use_High:
  "V  H  (Node E,V)  lift_Use_set Use E X H L"

  | lift_Use_Low:
  "V  L  (Node X,V)  lift_Use_set Use E X H L"


abbreviation lift_Use :: "('node  'var set)  'node  'node  
                       'var set  'var set  'node LDCFG_node  'var set"
  where "lift_Use Use E X H L n  {V. (n,V)  lift_Use_set Use E X H L}"


fun lift_ParamUses :: "('node  'var set list)  'node LDCFG_node  'var set list"
  where "lift_ParamUses ParamUses (Node n) =  ParamUses n"
  | "lift_ParamUses ParamUses NewEntry = []"
  | "lift_ParamUses ParamUses NewExit = []"


fun lift_ParamDefs :: "('node  'var list)  'node LDCFG_node  'var list"
  where "lift_ParamDefs ParamDefs (Node n) =  ParamDefs n"
  | "lift_ParamDefs ParamDefs NewEntry = []"
  | "lift_ParamDefs ParamDefs NewExit = []"



subsection ‹The lifting lemmas›


subsubsection ‹Lifting the CFG locales›

abbreviation src :: "('edge,'node,'var,'val,'ret,'pname) LDCFG_edge  'node LDCFG_node"
  where "src a  fst a"

abbreviation trg :: "('edge,'node,'var,'val,'ret,'pname) LDCFG_edge  'node LDCFG_node"
  where "trg a  snd(snd a)"

abbreviation knd :: "('edge,'node,'var,'val,'ret,'pname) LDCFG_edge  
  ('var,'val,'ret,'pname) edge_kind"
  where "knd a  fst(snd a)"


lemma lift_CFG:
  assumes wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit"
  shows "CFG src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main"
proof -
  interpret CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule wf)
  interpret Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit
    by(rule pd)
  show ?thesis
  proof
    fix a assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "trg a = NewEntry"
    thus False by(fastforce elim:lift_valid_edge.cases)
  next
    show "lift_get_proc get_proc Main NewEntry = Main" by simp
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "src a = NewEntry"
    thus False by(fastforce elim:lift_valid_edge.cases)
  next
    fix a a' 
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
      and "src a = src a'" and "trg a = trg a'"
    thus "a = a'"
    proof(induct rule:lift_valid_edge.induct)
      case lve_edge thus ?case by -(erule lift_valid_edge.cases,auto dest:edge_det)
    qed(auto elim:lift_valid_edge.cases)
  next
    fix a Q r f
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘Mainf"
    thus False by(fastforce elim:lift_valid_edge.cases dest:Main_no_call_target)
  next
    fix a Q' f'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘Mainf'"
    thus False by(fastforce elim:lift_valid_edge.cases dest:Main_no_return_source)
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    thus "ins outs. (p, ins, outs)  set procs"
      by(fastforce elim:lift_valid_edge.cases intro:callee_in_procs)
  next
    fix a assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "intra_kind (knd a)"
    thus "lift_get_proc get_proc Main (src a) = lift_get_proc get_proc Main (trg a)"
      by(fastforce elim:lift_valid_edge.cases intro:get_proc_intra 
                  simp:get_proc_Entry get_proc_Exit)
  next
    fix a Q r p fs 
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    thus "lift_get_proc get_proc Main (trg a) = p"
      by(fastforce elim:lift_valid_edge.cases intro:get_proc_call)
  next
    fix a Q' p f'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'"
    thus "lift_get_proc get_proc Main (src a) = p"
      by(fastforce elim:lift_valid_edge.cases intro:get_proc_return)
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    then obtain ax where "valid_edge ax" and "kind ax = Q:r↪⇘pfs"
      and "sourcenode ax  Entry  targetnode ax  Exit"
      and "src a = Node (sourcenode ax)" and "trg a = Node (targetnode ax)"
      by(fastforce elim:lift_valid_edge.cases)
    from valid_edge ax kind ax = Q:r↪⇘pfs
    have all:"a'. valid_edge a'  targetnode a' = targetnode ax  
               (Qx rx fsx. kind a' = Qx:rx↪⇘pfsx)"
      by(auto dest:call_edges_only)
    { fix a' 
      assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
        and "trg a' = trg a"
      hence "Qx rx fsx. knd a' = Qx:rx↪⇘pfsx"
      proof(induct rule:lift_valid_edge.induct)
        case (lve_edge ax' e)
        note [simp] = e = (Node (sourcenode ax'), kind ax', Node (targetnode ax'))
        from trg e = trg a trg a = Node (targetnode ax)
        have "targetnode ax' = targetnode ax" by simp
        with valid_edge ax' all have "Qx rx fsx. kind ax' = Qx:rx↪⇘pfsx" by blast
        thus ?case by simp
      next
        case (lve_Entry_edge e)
        from e = (NewEntry, (λs. True), Node Entry) trg e = trg a
          trg a = Node (targetnode ax)
        have "targetnode ax = Entry" by simp
        with valid_edge ax have False by(rule Entry_target)
        thus ?case by simp
      next
        case (lve_Exit_edge e)
        from e = (Node Exit, (λs. True), NewExit) trg e = trg a
          trg a = Node (targetnode ax) have False by simp
        thus ?case by simp
      next
        case (lve_Entry_Exit_edge e)
        from e = (NewEntry,(λs. False),NewExit) trg e = trg a
          trg a = Node (targetnode ax) have False by simp
        thus ?case by simp
      qed }
    thus "a'. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a' 
               trg a' = trg a  (Qx rx fsx. knd a' = Qx:rx↪⇘pfsx)" by simp
  next
    fix a Q' p f'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'"
    then obtain ax where "valid_edge ax" and "kind ax = Q'↩⇘pf'"
      and "sourcenode ax  Entry  targetnode ax  Exit"
      and "src a = Node (sourcenode ax)" and "trg a = Node (targetnode ax)"
      by(fastforce elim:lift_valid_edge.cases)
    from valid_edge ax kind ax = Q'↩⇘pf'
    have all:"a'. valid_edge a'  sourcenode a' = sourcenode ax  
            (Qx fx. kind a' = Qx↩⇘pfx)"
      by(auto dest:return_edges_only)
    { fix a' 
      assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
        and "src a' = src a"
      hence "Qx fx. knd a' = Qx↩⇘pfx"
      proof(induct rule:lift_valid_edge.induct)
        case (lve_edge ax' e)
        note [simp] = e = (Node (sourcenode ax'), kind ax', Node (targetnode ax'))
        from src e = src a src a = Node (sourcenode ax)
        have "sourcenode ax' = sourcenode ax" by simp
        with valid_edge ax' all have "Qx fx. kind ax' = Qx↩⇘pfx" by blast
        thus ?case by simp
      next
        case (lve_Entry_edge e)
        from e = (NewEntry, (λs. True), Node Entry) src e = src a
          src a = Node (sourcenode ax) have False by simp
        thus ?case by simp
      next
        case (lve_Exit_edge e)
        from e = (Node Exit, (λs. True), NewExit) src e = src a
          src a = Node (sourcenode ax) have "sourcenode ax = Exit" by simp
        with valid_edge ax have False by(rule Exit_source)
        thus ?case by simp
      next
        case (lve_Entry_Exit_edge e)
        from e = (NewEntry,(λs. False),NewExit) src e = src a
          src a = Node (sourcenode ax) have False by simp
        thus ?case by simp
      qed }
    thus "a'. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a' 
               src a' = src a  (Qx fx. knd a' = Qx↩⇘pfx)" by simp
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    thus "lift_get_return_edges get_return_edges valid_edge 
      sourcenode targetnode kind a  {}"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge ax e)
      from e = (Node (sourcenode ax), kind ax, Node (targetnode ax)) 
        knd e = Q:r↪⇘pfs
      have "kind ax = Q:r↪⇘pfs" by simp
      with valid_edge ax have "get_return_edges ax  {}"
        by(rule get_return_edge_call)
      then obtain ax' where "ax'  get_return_edges ax" by blast
      with e = (Node (sourcenode ax), kind ax, Node (targetnode ax)) valid_edge ax
      have "(Node (sourcenode ax'),kind ax',Node (targetnode ax'))  
        lift_get_return_edges get_return_edges valid_edge 
        sourcenode targetnode kind e"
        by(fastforce intro:lift_get_return_edgesI)
      thus ?case by fastforce
    qed simp_all
  next
    fix a a'
    assume "a'  lift_get_return_edges get_return_edges valid_edge 
      sourcenode targetnode kind a"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
    proof (induct rule:lift_get_return_edges.induct)
      case (lift_get_return_edgesI ax a' e')
      from valid_edge ax a'  get_return_edges ax have "valid_edge a'" 
        by(rule get_return_edges_valid)
      from valid_edge ax a'  get_return_edges ax obtain Q r p fs 
        where "kind ax = Q:r↪⇘pfs" by(fastforce dest!:only_call_get_return_edges)
      with valid_edge ax a'  get_return_edges ax obtain Q' f' 
        where "kind a' = Q'↩⇘pf'" by(fastforce dest!:call_return_edges)
      from valid_edge a' kind a' = Q'↩⇘pf' have "get_proc(sourcenode a') = p"
        by(rule get_proc_return)
      have "sourcenode a'  Entry"
      proof
        assume "sourcenode a' = Entry"
        with get_proc_Entry get_proc(sourcenode a') = p have "p = Main" by simp
        with kind a' = Q'↩⇘pf' have "kind a' = Q'↩⇘Mainf'" by simp
        with valid_edge a' show False by(rule Main_no_return_source)
      qed
      with e' = (Node (sourcenode a'), kind a', Node (targetnode a')) 
        valid_edge a'
      show ?case by(fastforce intro:lve_edge)
    qed
  next
    fix a a'
    assume "a'  lift_get_return_edges get_return_edges valid_edge sourcenode
      targetnode kind a"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "Q r p fs. knd a = Q:r↪⇘pfs"
    proof (induct rule:lift_get_return_edges.induct)
      case (lift_get_return_edgesI ax a' e') 
      from valid_edge ax a'  get_return_edges ax 
      have "Q r p fs. kind ax = Q:r↪⇘pfs"
        by(rule only_call_get_return_edges)
      with a = (Node (sourcenode ax), kind ax, Node (targetnode ax))
      show ?case by simp
    qed
  next
    fix a Q r p fs a'
    assume "a'  lift_get_return_edges get_return_edges 
      valid_edge sourcenode targetnode kind a" and "knd a = Q:r↪⇘pfs"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "Q' f'. knd a' = Q'↩⇘pf'"
    proof (induct rule:lift_get_return_edges.induct)
      case (lift_get_return_edgesI ax a' e')
      from a = (Node (sourcenode ax), kind ax, Node (targetnode ax))
        knd a = Q:r↪⇘pfs
      have "kind ax = Q:r↪⇘pfs" by simp
      with valid_edge ax a'  get_return_edges ax have "Q' f'. kind a' = Q'↩⇘pf'"
        by -(rule call_return_edges)
      with e' = (Node (sourcenode a'), kind a', Node (targetnode a'))
      show ?case by simp
    qed
  next
    fix a Q' p f'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'"
    thus "∃!a'. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a' 
      (Q r fs. knd a' = Q:r↪⇘pfs)  a  lift_get_return_edges get_return_edges 
      valid_edge sourcenode targetnode kind a'"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
        knd e = Q'↩⇘pf' have "kind a = Q'↩⇘pf'" by simp
      with valid_edge a
      have "∃!a'. valid_edge a'  (Q r fs. kind a' = Q:r↪⇘pfs)  
        a  get_return_edges a'"
        by(rule return_needs_call)
      then obtain a' Q r fs where "valid_edge a'" and "kind a' = Q:r↪⇘pfs"
        and "a  get_return_edges a'"
        and imp:"x. valid_edge x  (Q r fs. kind x = Q:r↪⇘pfs)  
        a  get_return_edges x  x = a'"
        by(fastforce elim:ex1E)
      let ?e' = "(Node (sourcenode a'),kind a',Node (targetnode a'))"
      have "sourcenode a'  Entry"
      proof
        assume "sourcenode a' = Entry"
        with valid_edge a' kind a' = Q:r↪⇘pfs
        show False by(rule Entry_no_call_source)
      qed
      with valid_edge a'
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e'"
        by(fastforce intro:lift_valid_edge.lve_edge)
      moreover
      from kind a' = Q:r↪⇘pfs have "knd ?e' = Q:r↪⇘pfs" by simp
      moreover
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) 
        valid_edge a' a  get_return_edges a'
      have "e  lift_get_return_edges get_return_edges valid_edge
        sourcenode targetnode kind ?e'" by(fastforce intro:lift_get_return_edgesI)
      moreover
      { fix x
        assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x"
          and "Q r fs. knd x = Q:r↪⇘pfs" 
          and "e  lift_get_return_edges get_return_edges valid_edge
          sourcenode targetnode kind x"
        from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x
          Q r fs. knd x = Q:r↪⇘pfs obtain y where "valid_edge y" 
          and "x = (Node (sourcenode y), kind y, Node (targetnode y))"
          by(fastforce elim:lift_valid_edge.cases)
        with e  lift_get_return_edges get_return_edges valid_edge
          sourcenode targetnode kind x valid_edge a
          e = (Node (sourcenode a), kind a, Node (targetnode a))
        have "x = ?e'"
        proof(induct rule:lift_get_return_edges.induct)
          case (lift_get_return_edgesI ax ax' e)
          from valid_edge ax ax'  get_return_edges ax have "valid_edge ax'"
            by(rule get_return_edges_valid)
          from e = (Node (sourcenode ax'), kind ax', Node (targetnode ax'))
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "sourcenode a = sourcenode ax'" and "targetnode a = targetnode ax'"
            by simp_all
          with valid_edge a valid_edge ax' have [simp]:"a = ax'" by(rule edge_det)
          from x = (Node (sourcenode ax), kind ax, Node (targetnode ax))
            Q r fs. knd x = Q:r↪⇘pfs have "Q r fs. kind ax = Q:r↪⇘pfs" by simp
          with valid_edge ax ax'  get_return_edges ax imp
          have "ax = a'" by fastforce
          with x = (Node (sourcenode ax), kind ax, Node (targetnode ax)) 
          show ?thesis by simp
        qed }
      ultimately show ?case by(blast intro:ex1I)
    qed simp_all
  next
    fix a a'
    assume "a'  lift_get_return_edges get_return_edges valid_edge sourcenode
      targetnode kind a" 
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "a''. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'' 
      src a'' = trg a  trg a'' = src a'  knd a'' = (λcf. False)"
    proof(induct rule:lift_get_return_edges.induct)
      case (lift_get_return_edgesI ax a' e')
      from valid_edge ax a'  get_return_edges ax
      obtain ax' where "valid_edge ax'" and "sourcenode ax' = targetnode ax"
        and "targetnode ax' = sourcenode a'" and "kind ax' = (λcf. False)"
        by(fastforce dest:intra_proc_additional_edge)
      let ?ex = "(Node (sourcenode ax'), kind ax', Node (targetnode ax'))"
      have "targetnode ax  Entry"
      proof
        assume "targetnode ax = Entry"
        with valid_edge ax show False by(rule Entry_target)
      qed
      with sourcenode ax' = targetnode ax have "sourcenode ax'  Entry" by simp
      with valid_edge ax' 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?ex"
        by(fastforce intro:lve_edge)
      with e' = (Node (sourcenode a'), kind a', Node (targetnode a'))
        a = (Node (sourcenode ax), kind ax, Node (targetnode ax))
        e' = (Node (sourcenode a'), kind a', Node (targetnode a'))
        sourcenode ax' = targetnode ax targetnode ax' = sourcenode a'
        kind ax' = (λcf. False)
      show ?case by simp
    qed
  next
    fix a a'
    assume "a'  lift_get_return_edges get_return_edges valid_edge sourcenode
      targetnode kind a" 
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "a''. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'' 
      src a'' = src a  trg a'' = trg a'  knd a'' = (λcf. False)"
    proof(induct rule:lift_get_return_edges.induct)
      case (lift_get_return_edgesI ax a' e')
      from valid_edge ax a'  get_return_edges ax
      obtain ax' where "valid_edge ax'" and "sourcenode ax' = sourcenode ax"
        and "targetnode ax' = targetnode a'" and "kind ax' = (λcf. False)"
        by(fastforce dest:call_return_node_edge)
      let ?ex = "(Node (sourcenode ax'), kind ax', Node (targetnode ax'))"
      from valid_edge ax a'  get_return_edges ax
      obtain Q r p fs where "kind ax = Q:r↪⇘pfs" 
        by(fastforce dest!:only_call_get_return_edges)
      have "sourcenode ax  Entry"
      proof
        assume "sourcenode ax = Entry"
        with valid_edge ax kind ax = Q:r↪⇘pfs show False
          by(rule Entry_no_call_source)
      qed
      with sourcenode ax' = sourcenode ax have "sourcenode ax'  Entry" by simp
      with valid_edge ax' 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?ex"
        by(fastforce intro:lve_edge)
      with e' = (Node (sourcenode a'), kind a', Node (targetnode a'))
        a = (Node (sourcenode ax), kind ax, Node (targetnode ax))
        e' = (Node (sourcenode a'), kind a', Node (targetnode a'))
        sourcenode ax' = sourcenode ax targetnode ax' = targetnode a'
        kind ax' = (λcf. False)
      show ?case by simp
    qed
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    thus "∃!a'. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a' 
      src a' = src a  intra_kind (knd a')"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
      have "kind a = Q:r↪⇘pfs" by simp
      with valid_edge a have "∃!a'. valid_edge a'  sourcenode a' = sourcenode a 
        intra_kind(kind a')" by(rule call_only_one_intra_edge)
      then obtain a' where "valid_edge a'" and "sourcenode a' = sourcenode a"
        and "intra_kind(kind a')" 
        and imp:"x. valid_edge x  sourcenode x = sourcenode a  intra_kind(kind x)
         x = a'" by(fastforce elim:ex1E)
      let ?e' = "(Node (sourcenode a'), kind a', Node (targetnode a'))"
      have "sourcenode a  Entry"
      proof
        assume "sourcenode a = Entry"
        with valid_edge a kind a = Q:r↪⇘pfs show False
          by(rule Entry_no_call_source)
      qed
      with sourcenode a' = sourcenode a have "sourcenode a'  Entry" by simp
      with valid_edge a' 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e'"
        by(fastforce intro:lift_valid_edge.lve_edge)
      moreover
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
        sourcenode a' = sourcenode a
      have "src ?e' = src e" by simp
      moreover
      from intra_kind(kind a') have "intra_kind (knd ?e')" by simp
      moreover
      { fix x 
        assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x"
          and "src x = src e" and "intra_kind (knd x)"
        from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x
        have "x = ?e'"
        proof(induct rule:lift_valid_edge.cases)
          case (lve_edge ax ex)
          from intra_kind (knd x) x = ex src x = src e
            ex = (Node (sourcenode ax), kind ax, Node (targetnode ax))
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "intra_kind (kind ax)" and "sourcenode ax = sourcenode a" by simp_all
          with valid_edge ax imp have "ax = a'" by fastforce
          with x = ex ex = (Node (sourcenode ax), kind ax, Node (targetnode ax))
          show ?case by simp
        next
          case (lve_Entry_edge ex)
          with src x = src e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have False by simp
          thus ?case by simp
        next
          case (lve_Exit_edge ex)
          with src x = src e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "sourcenode a = Exit" by simp
          with valid_edge a have False by(rule Exit_source)
          thus ?case by simp
        next
          case (lve_Entry_Exit_edge ex)
          with src x = src e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have False by simp
          thus ?case by simp
        qed }
      ultimately show ?case by(blast intro:ex1I)
    qed simp_all
  next
    fix a Q' p f'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'"
    thus "∃!a'. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a' 
      trg a' = trg a  intra_kind (knd a')"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q'↩⇘pf'
      have "kind a = Q'↩⇘pf'" by simp
      with valid_edge a have "∃!a'. valid_edge a'  targetnode a' = targetnode a 
        intra_kind(kind a')" by(rule return_only_one_intra_edge)
      then obtain a' where "valid_edge a'" and "targetnode a' = targetnode a"
        and "intra_kind(kind a')" 
        and imp:"x. valid_edge x  targetnode x = targetnode a  intra_kind(kind x)
         x = a'" by(fastforce elim:ex1E)
      let ?e' = "(Node (sourcenode a'), kind a', Node (targetnode a'))"
      have "targetnode a  Exit"
      proof
        assume "targetnode a = Exit"
        with valid_edge a kind a = Q'↩⇘pf' show False
          by(rule Exit_no_return_target)
      qed
      with targetnode a' = targetnode a have "targetnode a'  Exit" by simp
      with valid_edge a' 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e'"
        by(fastforce intro:lift_valid_edge.lve_edge)
      moreover
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
        targetnode a' = targetnode a
      have "trg ?e' = trg e" by simp
      moreover
      from intra_kind(kind a') have "intra_kind (knd ?e')" by simp
      moreover
      { fix x 
        assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x"
          and "trg x = trg e" and "intra_kind (knd x)"
        from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit x
        have "x = ?e'"
        proof(induct rule:lift_valid_edge.cases)
          case (lve_edge ax ex)
          from intra_kind (knd x) x = ex trg x = trg e
            ex = (Node (sourcenode ax), kind ax, Node (targetnode ax))
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "intra_kind (kind ax)" and "targetnode ax = targetnode a" by simp_all
          with valid_edge ax imp have "ax = a'" by fastforce
          with x = ex ex = (Node (sourcenode ax), kind ax, Node (targetnode ax))
          show ?case by simp
        next
          case (lve_Entry_edge ex)
          with trg x = trg e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "targetnode a = Entry" by simp
          with valid_edge a have False by(rule Entry_target)
          thus ?case by simp
        next
          case (lve_Exit_edge ex)
          with trg x = trg e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have False by simp
          thus ?case by simp
        next
          case (lve_Entry_Exit_edge ex)
          with trg x = trg e 
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have False by simp
          thus ?case by simp
        qed }
      ultimately show ?case by(blast intro:ex1I)
    qed simp_all
  next
    fix a a' Q1 r1 p fs1 Q2 r2 fs2
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
      and "knd a = Q1:r1↪⇘pfs1" and "knd a' = Q2:r2↪⇘pfs2"
    then obtain x x' where "valid_edge x" 
      and a:"a = (Node (sourcenode x),kind x,Node (targetnode x))" and "valid_edge x'"
      and a':"a' = (Node (sourcenode x'),kind x',Node (targetnode x'))"
      by(auto elim!:lift_valid_edge.cases)
    with knd a = Q1:r1↪⇘pfs1 knd a' = Q2:r2↪⇘pfs2
    have "kind x = Q1:r1↪⇘pfs1" and "kind x' = Q2:r2↪⇘pfs2" by simp_all
    with valid_edge x valid_edge x' have "targetnode x = targetnode x'"
      by(rule same_proc_call_unique_target)
    with a a' show "trg a = trg a'" by simp
  next
    from unique_callers show "distinct_fst procs" .
  next
    fix p ins outs
    assume "(p, ins, outs)  set procs"
    from distinct_formal_ins[OF this] show "distinct ins" .
  next
    fix p ins outs
    assume "(p, ins, outs)  set procs"
    from distinct_formal_outs[OF this] show "distinct outs" .
  qed
qed


lemma lift_CFG_wf:
  assumes wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit"
  shows "CFG_wf src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main (lift_Def Def Entry Exit H L) (lift_Use Use Entry Exit H L)
  (lift_ParamDefs ParamDefs) (lift_ParamUses ParamUses)"
proof -
  interpret CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule wf)
  interpret Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit
    by(rule pd)
  interpret CFG:CFG src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main" 
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main
    by(fastforce intro:lift_CFG wf pd)
  show ?thesis
  proof
    show "lift_Def Def Entry Exit H L NewEntry = {} 
          lift_Use Use Entry Exit H L NewEntry = {}"
      by(fastforce elim:lift_Use_set.cases lift_Def_set.cases)
  next
    fix a Q r p fs ins outs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "(p, ins, outs)  set procs"
    thus "length (lift_ParamUses ParamUses (src a)) = length ins"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
      have "kind a = Q:r↪⇘pfs" and "src e = Node (sourcenode a)" by simp_all
      with valid_edge a (p,ins,outs)  set procs
      have "length(ParamUses (sourcenode a)) = length ins"
        by -(rule ParamUses_call_source_length)
      with src e = Node (sourcenode a) show ?case by simp
    qed simp_all
  next
    fix a assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
    thus "distinct (lift_ParamDefs ParamDefs (trg a))"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from valid_edge a have "distinct (ParamDefs (targetnode a))"
        by(rule distinct_ParamDefs)
      with e = (Node (sourcenode a), kind a, Node (targetnode a))
      show ?case by simp
    next
      case (lve_Entry_edge e)
      have "ParamDefs Entry = []"
      proof(rule ccontr)
        assume "ParamDefs Entry  []"
        then obtain V Vs where "ParamDefs Entry = V#Vs" 
          by(cases "ParamDefs Entry") auto
        hence "V  set (ParamDefs Entry)" by fastforce
        hence "V  Def Entry" by(fastforce intro:ParamDefs_in_Def)
        with Entry_empty show False by simp
      qed
      with e = (NewEntry, (λs. True), Node Entry) show ?case by simp
    qed simp_all
  next
    fix a Q' p f' ins outs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'" and "(p, ins, outs)  set procs"
    thus "length (lift_ParamDefs ParamDefs (trg a)) = length outs"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
        knd e = Q'↩⇘pf'
      have "kind a = Q'↩⇘pf'" and "trg e = Node (targetnode a)" by simp_all
      with valid_edge a (p,ins,outs)  set procs
      have "length(ParamDefs (targetnode a)) = length outs"
        by -(rule ParamDefs_return_target_length)
      with trg e = Node (targetnode a) show ?case by simp
    qed simp_all
  next
    fix n V
    assume "CFG.CFG.valid_node src trg 
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) n"
      and "V  set (lift_ParamDefs ParamDefs n)"
    hence "((n = NewEntry)  n = NewExit)  (m. n = Node m  valid_node m)"
      by(auto elim:lift_valid_edge.cases simp:CFG.valid_node_def)
    thus "V  lift_Def Def Entry Exit H L n" apply -
    proof(erule disjE)+
      assume "n = NewEntry"
      with V  set (lift_ParamDefs ParamDefs n) show ?thesis by simp
    next
       assume "n = NewExit"
      with V  set (lift_ParamDefs ParamDefs n) show ?thesis by simp
    next
      assume "m. n = Node m  valid_node m"
      then obtain m where "n = Node m" and "valid_node m" by blast
      from n = Node m V  set (lift_ParamDefs ParamDefs n)
      have "V  set (ParamDefs m)" by simp
      with valid_node m have "V  Def m" by(rule ParamDefs_in_Def)
      with n = Node m show ?thesis by(fastforce intro:lift_Def_node)
    qed
  next
    fix a Q r p fs ins outs V
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "(p, ins, outs)  set procs" and "V  set ins"
    thus "V  lift_Def Def Entry Exit H L (trg a)"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
      have "kind a = Q:r↪⇘pfs" by simp
      from valid_edge a kind a = Q:r↪⇘pfs (p, ins, outs)  set procs V  set ins
      have "V  Def (targetnode a)" by(rule ins_in_Def)
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
      have "trg e = Node (targetnode a)" by simp
      with V  Def (targetnode a) show ?case by(fastforce intro:lift_Def_node)
    qed simp_all
  next
    fix a Q r p fs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs"
    thus "lift_Def Def Entry Exit H L (src a) = {}"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      show ?case
      proof(rule ccontr)
        assume "lift_Def Def Entry Exit H L (src e)  {}"
        then obtain x where "x  lift_Def Def Entry Exit H L (src e)" by blast
        from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
        have "kind a = Q:r↪⇘pfs" by simp
        with valid_edge a have "Def (sourcenode a) = {}" 
          by(rule call_source_Def_empty)
        have "sourcenode a  Entry"
        proof
          assume "sourcenode a = Entry"
          with valid_edge a kind a = Q:r↪⇘pfs
          show False by(rule Entry_no_call_source)
        qed
        from e = (Node (sourcenode a), kind a, Node (targetnode a))
        have "src e = Node (sourcenode a)" by simp
        with Def (sourcenode a) = {} x  lift_Def Def Entry Exit H L (src e)
          sourcenode a  Entry
        show False by(fastforce elim:lift_Def_set.cases)
      qed 
    qed simp_all
  next
    fix n V
    assume "CFG.CFG.valid_node src trg 
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) n"
      and "V  (set (lift_ParamUses ParamUses n))"
    hence "((n = NewEntry)  n = NewExit)  (m. n = Node m  valid_node m)"
      by(auto elim:lift_valid_edge.cases simp:CFG.valid_node_def)
    thus "V  lift_Use Use Entry Exit H L n" apply -
    proof(erule disjE)+
      assume "n = NewEntry"
      with V  (set (lift_ParamUses ParamUses n)) show ?thesis by simp
    next
      assume "n = NewExit"
      with V  (set (lift_ParamUses ParamUses n)) show ?thesis by simp
    next
      assume "m. n = Node m  valid_node m"
      then obtain m where "n = Node m" and "valid_node m" by blast
      from V  (set (lift_ParamUses ParamUses n)) n = Node m
      have "V  (set (ParamUses m))" by simp
      with valid_node m have "V  Use m" by(rule ParamUses_in_Use)
      with n = Node m show ?thesis by(fastforce intro:lift_Use_node)
    qed
  next
    fix a Q p f ins outs V
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q↩⇘pf" and "(p, ins, outs)  set procs" and "V  set outs"
    thus "V  lift_Use Use Entry Exit H L (src a)"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q↩⇘pf
      have "kind a = Q↩⇘pf" by simp
      from valid_edge a kind a = Q↩⇘pf (p, ins, outs)  set procs V  set outs
      have "V  Use (sourcenode a)" by(rule outs_in_Use)
      from e = (Node (sourcenode a), kind a, Node (targetnode a))
      have "src e = Node (sourcenode a)" by simp
      with V  Use (sourcenode a) show ?case by(fastforce intro:lift_Use_node)
    qed simp_all
  next
    fix a V s
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "V  lift_Def Def Entry Exit H L (src a)" and "intra_kind (knd a)"
      and "pred (knd a) s"
    thus "state_val (transfer (knd a) s) V = state_val s V"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) 
        intra_kind (knd e) pred (knd e) s
      have "intra_kind (kind a)" and "pred (kind a) s" 
        and "knd e = kind a" and "src e = Node (sourcenode a)" by simp_all
      from V  lift_Def Def Entry Exit H L (src e) src e = Node (sourcenode a)
      have "V  Def (sourcenode a)" by (auto dest: lift_Def_node)
      from valid_edge a V  Def (sourcenode a) intra_kind (kind a) 
        pred (kind a) s
      have "state_val (transfer (kind a) s) V = state_val s V" 
        by(rule CFG_intra_edge_no_Def_equal)
      with knd e = kind a show ?case by simp
    next
      case (lve_Entry_edge e)
      from e = (NewEntry, (λs. True), Node Entry) pred (knd e) s
      show ?case by(cases s) auto
    next
      case (lve_Exit_edge e)
      from e = (Node Exit, (λs. True), NewExit) pred (knd e) s
      show ?case by(cases s) auto
    next
      case (lve_Entry_Exit_edge e)
      from e = (NewEntry, (λs. False), NewExit) pred (knd e) s
      have False by(cases s) auto
      thus ?case by simp
    qed
  next
    fix a s s'
    assume assms:"lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      "Vlift_Use Use Entry Exit H L (src a). state_val s V = state_val s' V"
      "intra_kind (knd a)" "pred (knd a) s" "pred (knd a) s'"
    show "Vlift_Def Def Entry Exit H L (src a).
      state_val (transfer (knd a) s) V = state_val (transfer (knd a) s') V"
    proof
      fix V assume "V  lift_Def Def Entry Exit H L (src a)"
      with assms
      show "state_val (transfer (knd a) s) V = state_val (transfer (knd a) s') V"
      proof(induct rule:lift_valid_edge.induct)
        case (lve_edge a e)
        from e = (Node (sourcenode a), kind a, Node (targetnode a))
          intra_kind (knd e) have "intra_kind (kind a)" by simp
        show ?case
        proof (cases "Node (sourcenode a) = Node Entry")
          case True
          hence "sourcenode a = Entry" by simp
          from Entry_Exit_edge obtain a' where "valid_edge a'"
            and "sourcenode a' = Entry" and "targetnode a' = Exit"
            and "kind a' = (λs. False)" by blast
          have "Q. kind a = (Q)"
          proof(cases "targetnode a = Exit")
            case True
            with valid_edge a valid_edge a' sourcenode a = Entry
              sourcenode a' = Entry targetnode a' = Exit
            have "a = a'" by(fastforce dest:edge_det)
            with kind a' = (λs. False) show ?thesis by simp
          next
            case False
            with valid_edge a valid_edge a' sourcenode a = Entry
              sourcenode a' = Entry targetnode a' = Exit
              intra_kind (kind a) kind a' = (λs. False)
            show ?thesis by(auto dest:deterministic simp:intra_kind_def)
          qed
          from True V  lift_Def Def Entry Exit H L (src e) Entry_empty
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "V  H" by(fastforce elim:lift_Def_set.cases)
          from True e = (Node (sourcenode a), kind a, Node (targetnode a))
            sourcenode a  Entry  targetnode a  Exit
          have "VH. V  lift_Use Use Entry Exit H L (src e)"
            by(fastforce intro:lift_Use_High)
          with Vlift_Use Use Entry Exit H L (src e). 
            state_val s V = state_val s' V V  H
          have "state_val s V = state_val s' V" by simp
          with e = (Node (sourcenode a), kind a, Node (targetnode a)) 
            Q. kind a = (Q) pred (knd e) s pred (knd e) s'
          show ?thesis by(cases s,auto,cases s',auto)
        next
          case False
          { fix V' assume "V'  Use (sourcenode a)"
            with e = (Node (sourcenode a), kind a, Node (targetnode a))
            have "V'  lift_Use Use Entry Exit H L (src e)"
              by(fastforce intro:lift_Use_node)
          }
          with Vlift_Use Use Entry Exit H L (src e). 
            state_val s V = state_val s' V
          have "VUse (sourcenode a). state_val s V = state_val s' V"
            by fastforce
          from valid_edge a this pred (knd e) s pred (knd e) s'
            e = (Node (sourcenode a), kind a, Node (targetnode a))
            intra_kind (knd e)
          have "V  Def (sourcenode a). state_val (transfer (kind a) s) V =
            state_val (transfer (kind a) s') V"
            by -(erule CFG_intra_edge_transfer_uses_only_Use,auto)
          from V  lift_Def Def Entry Exit H L (src e) False
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          have "V  Def (sourcenode a)" by(fastforce elim:lift_Def_set.cases)
          with V  Def (sourcenode a). state_val (transfer (kind a) s) V =
            state_val (transfer (kind a) s') V
            e = (Node (sourcenode a), kind a, Node (targetnode a))
          show ?thesis by simp
        qed
      next
        case (lve_Entry_edge e)
        from V  lift_Def Def Entry Exit H L (src e) 
          e = (NewEntry, (λs. True), Node Entry)
        have False by(fastforce elim:lift_Def_set.cases)
        thus ?case by simp
      next
        case (lve_Exit_edge e)
        from V  lift_Def Def Entry Exit H L (src e) 
          e = (Node Exit, (λs. True), NewExit)
        have False
          by(fastforce elim:lift_Def_set.cases intro!:Entry_noteq_Exit simp:Exit_empty)
        thus ?case  by simp
      next
        case (lve_Entry_Exit_edge e)
        thus ?case by(cases s) auto
      qed
    qed
  next
    fix a s s'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "pred (knd a) s" and "snd (hd s) = snd (hd s')"
      and "Vlift_Use Use Entry Exit H L (src a). state_val s V = state_val s' V"
      and "length s = length s'"
    thus "pred (knd a) s'"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) pred (knd e) s
      have "pred (kind a) s" and "src e = Node (sourcenode a)" by simp_all
      from src e = Node (sourcenode a) 
        Vlift_Use Use Entry Exit H L (src e). state_val s V = state_val s' V
      have "V  Use (sourcenode a). state_val s V = state_val s' V"
        by(auto dest:lift_Use_node)
      from valid_edge a pred (kind a) s snd (hd s) = snd (hd s')
        this length s = length s'
      have "pred (kind a) s'" by(rule CFG_edge_Uses_pred_equal)
      with e = (Node (sourcenode a), kind a, Node (targetnode a))
      show ?case by simp
    next
      case (lve_Entry_edge e)
      thus ?case by(cases s') auto
    next
      case (lve_Exit_edge e)
      thus ?case by(cases s') auto
    next
      case (lve_Entry_Exit_edge e)
      thus ?case by(cases s) auto
    qed
  next
    fix a Q r p fs ins outs
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "(p, ins, outs)  set procs"
    thus "length fs = length ins"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
      have "kind a = Q:r↪⇘pfs" by simp
      from valid_edge a kind a = Q:r↪⇘pfs (p, ins, outs)  set procs
      show ?case by(rule CFG_call_edge_length)
    qed simp_all
  next
    fix a Q r p fs a' Q' r' p' fs' s s'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "knd a' = Q':r'↪⇘p'fs'"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
      and "src a = src a'" and "pred (knd a) s" and "pred (knd a') s"
    from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a
      knd a = Q:r↪⇘pfs pred (knd a) s
    obtain x where a:"a = (Node (sourcenode x),kind x,Node (targetnode x))" 
      and "valid_edge x" and "src a = Node (sourcenode x)" 
      and "kind x = Q:r↪⇘pfs" and "pred (kind x) s"
      by(fastforce elim:lift_valid_edge.cases)
    from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'
      knd a' = Q':r'↪⇘p'fs' pred (knd a') s
    obtain x' where a':"a' = (Node (sourcenode x'),kind x',Node (targetnode x'))" 
      and "valid_edge x'" and "src a' = Node (sourcenode x')" 
      and "kind x' = Q':r'↪⇘p'fs'" and "pred (kind x') s"
      by(fastforce elim:lift_valid_edge.cases)
    from src a = Node (sourcenode x) src a' = Node (sourcenode x') 
      src a = src a'
    have "sourcenode x = sourcenode x'" by simp
    from valid_edge x kind x = Q:r↪⇘pfs valid_edge x' kind x' = Q':r'↪⇘p'fs'
      sourcenode x = sourcenode x' pred (kind x) s pred (kind x') s
    have "x = x'" by(rule CFG_call_determ)
    with a a' show "a = a'" by simp
  next
    fix a Q r p fs i ins outs s s'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q:r↪⇘pfs" and "i < length ins" and "(p, ins, outs)  set procs"
      and "pred (knd a) s" and "pred (knd a) s'"
      and "Vlift_ParamUses ParamUses (src a) ! i. state_val s V = state_val s' V"
    thus "params fs (state_val s) ! i = CFG.params fs (state_val s') ! i"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q:r↪⇘pfs
        pred (knd e) s pred (knd e) s'
      have "kind a = Q:r↪⇘pfs" and "pred (kind a) s" and "pred (kind a) s'"
        and "src e = Node (sourcenode a)"
        by simp_all
      from Vlift_ParamUses ParamUses (src e) ! i. state_val s V = state_val s' V
        src e = Node (sourcenode a)
      have "V  (ParamUses (sourcenode a))!i. state_val s V = state_val s' V" by simp
      with valid_edge a kind a = Q:r↪⇘pfs i < length ins 
        (p, ins, outs)  set procs pred (kind a) s pred (kind a) s'
      show ?case by(rule CFG_call_edge_params)
    qed simp_all
  next
    fix a Q' p f' ins outs cf cf'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q'↩⇘pf'" and "(p, ins, outs)  set procs"
    thus "f' cf cf' = cf'(lift_ParamDefs ParamDefs (trg a) [:=] map cf outs)"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) knd e = Q'↩⇘pf'
      have "kind a = Q'↩⇘pf'" and "trg e = Node (targetnode a)" by simp_all
      from valid_edge a kind a = Q'↩⇘pf' (p, ins, outs)  set procs
      have "f' cf cf' = cf'(ParamDefs (targetnode a) [:=] map cf outs)"
        by(rule CFG_return_edge_fun)
      with trg e = Node (targetnode a) show ?case by simp
    qed simp_all
  next
    fix a a'
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
      and "src a = src a'" and "trg a  trg a'"
      and "intra_kind (knd a)" and "intra_kind (knd a')"
    thus "Q Q'. knd a = (Q)  knd a' = (Q')  
                 (s. (Q s  ¬ Q' s)  (Q' s  ¬ Q s))"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'
        valid_edge a e = (Node (sourcenode a), kind a, Node (targetnode a))
        src e = src a' trg e  trg a' intra_kind (knd e) intra_kind (knd a')
      show ?case
      proof(induct rule:lift_valid_edge.induct)
        case lve_edge thus ?case by(auto dest:deterministic)
      next
        case (lve_Exit_edge e')
        from e = (Node (sourcenode a), kind a, Node (targetnode a))
          e' = (Node Exit, (λs. True), NewExit) src e = src e'
        have "sourcenode a = Exit" by simp
        with valid_edge a have False by(rule Exit_source)
        thus ?case by simp
      qed auto
    qed (fastforce elim:lift_valid_edge.cases)+
  qed
qed


lemma lift_CFGExit:
  assumes wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit"
  shows "CFGExit src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main NewExit"
proof -
  interpret CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule wf)
  interpret Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit
    by(rule pd)
  interpret CFG:CFG src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main" 
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main
    by(fastforce intro:lift_CFG wf pd)
  show ?thesis
  proof
    fix a assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "src a = NewExit"
    thus False by(fastforce elim:lift_valid_edge.cases)
  next
    show "lift_get_proc get_proc Main NewExit = Main" by simp
  next
    fix a Q p f
    assume "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      and "knd a = Q↩⇘pf" and "trg a = NewExit"
    thus False by(fastforce elim:lift_valid_edge.cases)
  next
    show "a. lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a 
      src a = NewEntry  trg a = NewExit  knd a = (λs. False)"
      by(fastforce intro:lve_Entry_Exit_edge)
  qed
qed


lemma lift_CFGExit_wf:
  assumes wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit"
  shows "CFGExit_wf src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main NewExit (lift_Def Def Entry Exit H L) (lift_Use Use Entry Exit H L)
  (lift_ParamDefs ParamDefs) (lift_ParamUses ParamUses)"
proof -
  interpret CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule wf)
  interpret Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit
    by(rule pd)
  interpret CFG_wf:CFG_wf src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main" 
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main "lift_Def Def Entry Exit H L" "lift_Use Use Entry Exit H L"
    "lift_ParamDefs ParamDefs" "lift_ParamUses ParamUses"
    by(fastforce intro:lift_CFG_wf wf pd)
  interpret CFGExit:CFGExit src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main"
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main NewExit 
    by(fastforce intro:lift_CFGExit wf pd)
  show ?thesis
  proof
    show "lift_Def Def Entry Exit H L NewExit = {} 
      lift_Use Use Entry Exit H L NewExit = {}" 
      by(fastforce elim:lift_Def_set.cases lift_Use_set.cases)
  qed
qed


subsubsection ‹Lifting the SDG›



lemma lift_Postdomination:
  assumes wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit"
  and inner:"CFGExit.inner_node sourcenode targetnode valid_edge Entry Exit nx"
  shows "Postdomination src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main NewExit"
proof -
  interpret CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule wf)
  interpret Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit
    by(rule pd)
  interpret CFGExit:CFGExit src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main"
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main NewExit 
    by(fastforce intro:lift_CFGExit wf pd)
  { fix m assume "valid_node m"
    then obtain a where "valid_edge a" and "m = sourcenode a  m = targetnode a"
      by(auto simp:valid_node_def)
    from m = sourcenode a  m = targetnode a
    have "CFG.CFG.valid_node src trg
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) (Node m)"
    proof
      assume "m = sourcenode a"
      show ?thesis
      proof(cases "m = Entry")
        case True
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (NewEntry,(λs. True),Node Entry)" by(fastforce intro:lve_Entry_edge)
        with m = Entry show ?thesis by(fastforce simp:CFGExit.valid_node_def)
      next
        case False
        with m = sourcenode a valid_edge a
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node (sourcenode a),kind a,Node(targetnode a))"
          by(fastforce intro:lve_edge)
        with m = sourcenode a show ?thesis by(fastforce simp:CFGExit.valid_node_def)
      qed
    next
      assume "m = targetnode a"
      show ?thesis
      proof(cases "m = Exit")
        case True
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node Exit,(λs. True),NewExit)" by(fastforce intro:lve_Exit_edge)
        with m = Exit show ?thesis by(fastforce simp:CFGExit.valid_node_def)
      next
        case False
        with m = targetnode a valid_edge a
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node (sourcenode a),kind a,Node(targetnode a))"
          by(fastforce intro:lve_edge)
        with m = targetnode a show ?thesis by(fastforce simp:CFGExit.valid_node_def)
      qed
    qed }
  note lift_valid_node = this
  { fix n as n' cs m m'
    assume "valid_path_aux cs as" and "m -as→* m'" and "c  set cs. valid_edge c"
      and "m  Entry  m'  Exit"
    hence "cs' es. CFG.CFG.valid_path_aux knd
      (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
      cs' es  
      list_all2 (λc c'. c' = (Node (sourcenode c),kind c,Node (targetnode c))) cs cs' 
        CFG.CFG.path src trg
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
      (Node m) es (Node m')"
    proof(induct arbitrary:m rule:vpa_induct)
      case (vpa_empty cs)
      from m -[]→* m' have [simp]:"m = m'" by fastforce
      from m -[]→* m' have "valid_node m" by(rule path_valid_node)
      obtain cs' where "cs' = 
        map (λc. (Node (sourcenode c),kind c,Node (targetnode c))) cs" by simp
      hence "list_all2 
        (λc c'. c' = (Node (sourcenode c),kind c,Node (targetnode c))) cs cs'"
        by(simp add:list_all2_conv_all_nth)
      with valid_node m show ?case
        apply(rule_tac x="cs'" in exI)
        apply(rule_tac x="[]" in exI)
        by(fastforce intro:CFGExit.empty_path lift_valid_node)
    next
      case (vpa_intra cs a as)
      note IH = m. m -as→* m'; cset cs. valid_edge c; m  Entry  m'  Exit 
        cs' es. CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) cs' es 
        list_all2 (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) cs
        cs'  CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) es (Node m')
      from m -a # as→* m' have "m = sourcenode a" and "valid_edge a"
        and "targetnode a -as→* m'" by(auto elim:path_split_Cons)
      show ?case
      proof(cases "sourcenode a = Entry  targetnode a = Exit")
        case True
        with m = sourcenode a m  Entry  m'  Exit
        have "m'  Exit" by simp
        from True have "targetnode a = Exit" by simp
        with targetnode a -as→* m' have "m' = Exit"
          by -(drule path_Exit_source,auto)
        with m'  Exit have False by simp
        thus ?thesis by simp
      next
        case False
        let ?e = "(Node (sourcenode a),kind a,Node (targetnode a))"
        from False valid_edge a 
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e"
          by(fastforce intro:lve_edge)
        have "targetnode a  Entry"
        proof
          assume "targetnode a = Entry"
          with valid_edge a show False by(rule Entry_target)
        qed
        hence "targetnode a  Entry  m'  Exit" by simp
        from IH[OF targetnode a -as→* m' cset cs. valid_edge c this] 
        obtain cs' es
          where valid_path:"CFG.valid_path_aux knd
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) cs' es" 
          and list:"list_all2 
          (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) cs cs'"
          and path:"CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node (targetnode a)) es (Node m')" by blast
        from intra_kind (kind a) valid_path have "CFG.valid_path_aux knd
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) cs' (?e#es)" by(fastforce simp:intra_kind_def)
        moreover
        from path m = sourcenode a 
          lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e
        have "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node m) (?e#es) (Node m')" by(fastforce intro:CFGExit.Cons_path)
        ultimately show ?thesis using list by blast
      qed
    next
      case (vpa_Call cs a as Q r p fs)
      note IH = m. m -as→* m'; cset (a # cs). valid_edge c; 
        m  Entry  m'  Exit 
        cs' es. CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) cs' es 
        list_all2 (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) 
        (a#cs) cs'  CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) es (Node m')
      from m -a # as→* m' have "m = sourcenode a" and "valid_edge a"
        and "targetnode a -as→* m'" by(auto elim:path_split_Cons)
      from cset cs. valid_edge c valid_edge a 
      have "cset (a # cs). valid_edge c" by simp
      let ?e = "(Node (sourcenode a),kind a,Node (targetnode a))"
      have "sourcenode a  Entry"
      proof
        assume "sourcenode a = Entry"
        with valid_edge a kind a = Q:r↪⇘pfs 
        show False by(rule Entry_no_call_source)
      qed
      with valid_edge a 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e"
        by(fastforce intro:lve_edge)
      have "targetnode a  Entry"
      proof
        assume "targetnode a = Entry"
        with valid_edge a show False by(rule Entry_target)
      qed
      hence "targetnode a  Entry  m'  Exit" by simp
      from IH[OF targetnode a -as→* m' cset (a # cs). valid_edge c this]
      obtain cs' es
        where valid_path:"CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode 
        targetnode kind) cs' es" 
        and list:"list_all2 
        (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) (a#cs) cs'"
        and path:"CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node (targetnode a)) es (Node m')" by blast
      from list obtain cx csx where "cs' = cx#csx"
        and cx:"cx = (Node (sourcenode a), kind a, Node (targetnode a))"
        and list':"list_all2 
        (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) cs csx"
        by(fastforce simp:list_all2_Cons1)
      from valid_path cx cs' = cx#csx kind a = Q:r↪⇘pfs
      have "CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode 
        targetnode kind) csx (?e#es)" by simp
      moreover
      from path m = sourcenode a 
        lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e
      have "CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) (?e#es) (Node m')" by(fastforce intro:CFGExit.Cons_path)
      ultimately show ?case using list' by blast
    next
      case (vpa_ReturnEmpty cs a as Q p f)
      note IH = m. m -as→* m'; cset []. valid_edge c; m  Entry  m'  Exit 
        cs' es. CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) cs' es 
        list_all2 (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) 
        [] cs'  CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) es (Node m')
      from m -a # as→* m' have "m = sourcenode a" and "valid_edge a"
        and "targetnode a -as→* m'" by(auto elim:path_split_Cons)
      let ?e = "(Node (sourcenode a),kind a,Node (targetnode a))"
      have "targetnode a  Exit"
      proof
        assume "targetnode a = Exit"
        with valid_edge a kind a = Q↩⇘pf show False by(rule Exit_no_return_target)
      qed
      with valid_edge a 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e"
        by(fastforce intro:lve_edge)
      have "targetnode a  Entry"
      proof
        assume "targetnode a = Entry"
        with valid_edge a show False by(rule Entry_target)
      qed
      hence "targetnode a  Entry  m'  Exit" by simp
      from IH[OF targetnode a -as→* m' _ this] obtain es
        where valid_path:"CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) [] es"
        and path:"CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node (targetnode a)) es (Node m')" by auto
      from valid_path kind a = Q↩⇘pf
      have "CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode 
        targetnode kind) [] (?e#es)" by simp
      moreover
      from path m = sourcenode a 
        lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e
      have "CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) (?e#es) (Node m')" by(fastforce intro:CFGExit.Cons_path)
      ultimately show ?case using cs = [] by blast
    next
      case (vpa_ReturnCons cs a as Q p f c' cs')
      note IH = m. m -as→* m'; cset cs'. valid_edge c; m  Entry  m'  Exit 
        csx es. CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) csx es 
        list_all2 (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) 
        cs' csx  CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) es (Node m')
      from m -a # as→* m' have "m = sourcenode a" and "valid_edge a"
        and "targetnode a -as→* m'" by(auto elim:path_split_Cons)
      from cset cs. valid_edge c cs = c' # cs'
      have "valid_edge c'" and "cset cs'. valid_edge c" by simp_all
      let ?e = "(Node (sourcenode a),kind a,Node (targetnode a))"
      have "targetnode a  Exit"
      proof
        assume "targetnode a = Exit"
        with valid_edge a kind a = Q↩⇘pf show False by(rule Exit_no_return_target)
      qed
      with valid_edge a 
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e"
        by(fastforce intro:lve_edge)
      have "targetnode a  Entry"
      proof
        assume "targetnode a = Entry"
        with valid_edge a show False by(rule Entry_target)
      qed
      hence "targetnode a  Entry  m'  Exit" by simp
      from IH[OF targetnode a -as→* m' cset cs'. valid_edge c this] 
      obtain csx es
        where valid_path:"CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind) csx es"
        and list:"list_all2 
        (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) cs' csx"
        and path:"CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node (targetnode a)) es (Node m')" by blast
      from valid_edge c' a  get_return_edges c'
      have "?e  lift_get_return_edges get_return_edges valid_edge sourcenode
        targetnode kind (Node (sourcenode c'),kind c',Node (targetnode c'))"
        by(fastforce intro:lift_get_return_edgesI)
      with valid_path kind a = Q↩⇘pf
      have "CFG.valid_path_aux knd
        (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
        ((Node (sourcenode c'),kind c',Node (targetnode c'))#csx) (?e#es)"
        by simp
      moreover
      from list cs = c' # cs'
      have "list_all2 
        (λc c'. c' = (Node (sourcenode c), kind c, Node (targetnode c))) cs 
        ((Node (sourcenode c'),kind c',Node (targetnode c'))#csx)"
        by simp
      moreover
      from path m = sourcenode a 
        lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit ?e
      have "CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (Node m) (?e#es) (Node m')" by(fastforce intro:CFGExit.Cons_path)
      ultimately show ?case using kind a = Q↩⇘pf by blast
    qed }
  hence lift_valid_path:"m as m'. m -as* m'; m  Entry  m'  Exit 
     es. CFG.CFG.valid_path' src trg knd
    (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
    (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
    (Node m) es (Node m')"
    by(fastforce simp:vp_def valid_path_def CFGExit.vp_def CFGExit.valid_path_def)
  show ?thesis
  proof
    fix n assume "CFG.CFG.valid_node src trg
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) n"
    hence "((n = NewEntry)  n = NewExit)  (m. n = Node m  valid_node m)"
      by(auto elim:lift_valid_edge.cases simp:CFGExit.valid_node_def)
    thus "as. CFG.CFG.valid_path' src trg knd
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
      (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
      NewEntry as n" apply -
    proof(erule disjE)+
      assume "n = NewEntry" 
      hence "CFG.CFG.valid_path' src trg knd
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
        NewEntry [] n"
        by(fastforce intro:CFGExit.empty_path 
          simp:CFGExit.vp_def CFGExit.valid_path_def)
      thus ?thesis by blast
    next
      assume "n = NewExit"
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
        (NewEntry,(λs. False),NewExit)" by(fastforce intro:lve_Entry_Exit_edge)
      hence "CFG.CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        NewEntry [(NewEntry,(λs. False),NewExit)] NewExit"
        by(fastforce dest:CFGExit.path_edge)
      with n = NewExit have "CFG.CFG.valid_path' src trg knd
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
        NewEntry [(NewEntry,(λs. False),NewExit)] n"
        by(fastforce simp:CFGExit.vp_def CFGExit.valid_path_def)
      thus ?thesis by blast
    next
      assume "m. n = Node m  valid_node m"
      then obtain m where "n = Node m" and "valid_node m" by blast
      from valid_node m
      show ?thesis
      proof(cases m rule:valid_node_cases)
        case Entry
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (NewEntry,(λs. True),Node Entry)" by(fastforce intro:lve_Entry_edge)
        with m = Entry n = Node m have "CFG.CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          NewEntry [(NewEntry,(λs. True),Node Entry)] n"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        thus ?thesis by(fastforce simp:CFGExit.vp_def CFGExit.valid_path_def)
      next
        case Exit
        from inner obtain ax where "valid_edge ax" and "intra_kind (kind ax)"
          and "inner_node (sourcenode ax)"
          and "targetnode ax = Exit" by(erule inner_node_Exit_edge)
        hence "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node (sourcenode ax),kind ax,Node Exit)"
          by(auto intro:lift_valid_edge.lve_edge simp:inner_node_def)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node (sourcenode ax)) [(Node (sourcenode ax),kind ax,Node Exit)] 
          (Node Exit)"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        with intra_kind (kind ax)
        have slp_edge:"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (Node (sourcenode ax)) [(Node (sourcenode ax),kind ax,Node Exit)] 
          (Node Exit)"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def 
            intra_kind_def)
        have "sourcenode ax  Exit"
        proof
          assume "sourcenode ax = Exit"
          with valid_edge ax show False by(rule Exit_source)
        qed
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (NewEntry,(λs. True),Node Entry)" by(fastforce intro:lve_Entry_edge)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (NewEntry) [(NewEntry,(λs. True),Node Entry)] (Node Entry)"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        hence slp_edge':"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (NewEntry) [(NewEntry,(λs. True),Node Entry)] (Node Entry)"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def)
        from inner_node (sourcenode ax) have "valid_node (sourcenode ax)"
          by(rule inner_is_valid)
        then obtain asx where "Entry -asx* sourcenode ax"
          by(fastforce dest:Entry_path)
        with sourcenode ax  Exit
        have "es. CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node Entry) es (Node (sourcenode ax))"
          by(fastforce intro:lift_valid_path)
        then obtain es where "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node Entry) es (Node (sourcenode ax))" by blast
        with slp_edge have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) 
          (Node Entry) (es@[(Node (sourcenode ax),kind ax,Node Exit)]) (Node Exit)"
          by -(rule CFGExit.vp_slp_Append)
        with slp_edge' have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) NewEntry
          ([(NewEntry,(λs. True),Node Entry)]@
          (es@[(Node (sourcenode ax),kind ax,Node Exit)])) (Node Exit)"
          by(rule CFGExit.slp_vp_Append)
        with m = Exit n = Node m show ?thesis by simp blast
      next
        case inner
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (NewEntry,(λs. True),Node Entry)" by(fastforce intro:lve_Entry_edge)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (NewEntry) [(NewEntry,(λs. True),Node Entry)] (Node Entry)"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        hence slp_edge:"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (NewEntry) [(NewEntry,(λs. True),Node Entry)] (Node Entry)"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def)
        from valid_node m obtain as where "Entry -as* m"
          by(fastforce dest:Entry_path)
        with inner_node m
        have "es. CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node Entry) es (Node m)"
          by(fastforce intro:lift_valid_path simp:inner_node_def)
        then obtain es where "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node Entry) es (Node m)" by blast
        with slp_edge have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) NewEntry ([(NewEntry,(λs. True),Node Entry)]@es) (Node m)"
          by(rule CFGExit.slp_vp_Append)
        with n = Node m show ?thesis by simp blast
      qed
    qed
  next
    fix n assume "CFG.CFG.valid_node src trg
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) n"
    hence "((n = NewEntry)  n = NewExit)  (m. n = Node m  valid_node m)"
      by(auto elim:lift_valid_edge.cases simp:CFGExit.valid_node_def)
    thus "as. CFG.CFG.valid_path' src trg knd
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
      (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
      n as NewExit" apply -
    proof(erule disjE)+
      assume "n = NewEntry"
      have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
        (NewEntry,(λs. False),NewExit)" by(fastforce intro:lve_Entry_Exit_edge)
      hence "CFG.CFG.path src trg
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        NewEntry [(NewEntry,(λs. False),NewExit)] NewExit"
        by(fastforce dest:CFGExit.path_edge)
      with n = NewEntry have "CFG.CFG.valid_path' src trg knd
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
        n [(NewEntry,(λs. False),NewExit)] NewExit"
        by(fastforce simp:CFGExit.vp_def CFGExit.valid_path_def)
      thus ?thesis by blast
    next
      assume "n = NewExit"
      hence "CFG.CFG.valid_path' src trg knd
        (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
        (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind)
        n [] NewExit"
        by(fastforce intro:CFGExit.empty_path 
          simp:CFGExit.vp_def CFGExit.valid_path_def)
      thus ?thesis by blast
    next
      assume "m. n = Node m  valid_node m"
      then obtain m where "n = Node m" and "valid_node m" by blast
      from valid_node m
      show ?thesis
      proof(cases m rule:valid_node_cases)
        case Entry
        from inner obtain ax where "valid_edge ax" and "intra_kind (kind ax)"
          and "inner_node (targetnode ax)" and "sourcenode ax = Entry" 
          by(erule inner_node_Entry_edge)
        hence "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node Entry,kind ax,Node (targetnode ax))"
          by(auto intro:lift_valid_edge.lve_edge simp:inner_node_def)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node Entry) [(Node Entry,kind ax,Node (targetnode ax))] 
          (Node (targetnode ax))"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        with intra_kind (kind ax)
        have slp_edge:"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (Node Entry) [(Node Entry,kind ax,Node (targetnode ax))] 
          (Node (targetnode ax))"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def 
            intra_kind_def)
        have "targetnode ax  Entry"
        proof
          assume "targetnode ax = Entry"
          with valid_edge ax show False by(rule Entry_target)
        qed
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node Exit,(λs. True),NewExit)" by(fastforce intro:lve_Exit_edge)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node Exit) [(Node Exit,(λs. True),NewExit)] NewExit"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        hence slp_edge':"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (Node Exit) [(Node Exit,(λs. True),NewExit)] NewExit"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def)
        from inner_node (targetnode ax) have "valid_node (targetnode ax)"
          by(rule inner_is_valid)
        then obtain asx where "targetnode ax -asx* Exit"
          by(fastforce dest:Exit_path)
        with targetnode ax  Entry
        have "es. CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node (targetnode ax)) es (Node Exit)"
          by(fastforce intro:lift_valid_path)
        then obtain es where "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node (targetnode ax)) es (Node Exit)" by blast
        with slp_edge have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) 
          (Node Entry) ([(Node Entry,kind ax,Node (targetnode ax))]@es) (Node Exit)"
          by(rule CFGExit.slp_vp_Append)
        with slp_edge' have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node Entry)
          (([(Node Entry,kind ax,Node (targetnode ax))]@es)@
          [(Node Exit,(λs. True),NewExit)]) NewExit"
          by -(rule CFGExit.vp_slp_Append)
        with m = Entry n = Node m show ?thesis by simp blast
      next
        case Exit
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node Exit,(λs. True),NewExit)" by(fastforce intro:lve_Exit_edge)
        with m = Exit n = Node m have "CFG.CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          n [(Node Exit,(λs. True),NewExit)] NewExit"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        thus ?thesis by(fastforce simp:CFGExit.vp_def CFGExit.valid_path_def)
      next
        case inner
        have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit
          (Node Exit,(λs. True),NewExit)" by(fastforce intro:lve_Exit_edge)
        hence "CFG.path src trg
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (Node Exit) [(Node Exit,(λs. True),NewExit)] NewExit"
          by(fastforce intro:CFGExit.Cons_path CFGExit.empty_path
                       simp:CFGExit.valid_node_def)
        hence slp_edge:"CFG.CFG.same_level_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind)
          (Node Exit) [(Node Exit,(λs. True),NewExit)] NewExit"
          by(fastforce simp:CFGExit.slp_def CFGExit.same_level_path_def)
        from valid_node m obtain as where "m -as* Exit"
          by(fastforce dest:Exit_path)
        with inner_node m
        have "es. CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node m) es (Node Exit)"
          by(fastforce intro:lift_valid_path simp:inner_node_def)
        then obtain es where "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node m) es (Node Exit)" by blast
        with slp_edge have "CFG.CFG.valid_path' src trg knd
          (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit)
          (lift_get_return_edges get_return_edges valid_edge sourcenode 
          targetnode kind) (Node m) (es@[(Node Exit,(λs. True),NewExit)]) NewExit"
          by -(rule CFGExit.vp_slp_Append)
        with n = Node m show ?thesis by simp blast
      qed
    qed
  next
    fix n n'
    assume method_exit1:"CFGExit.CFGExit.method_exit src knd
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewExit n"
      and method_exit2:"CFGExit.CFGExit.method_exit src knd
      (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewExit n'"
      and lift_eq:"lift_get_proc get_proc Main n = lift_get_proc get_proc Main n'"
    from method_exit1 show "n = n'"
    proof(rule CFGExit.method_exit_cases)
      assume "n = NewExit"
      from method_exit2 show ?thesis
      proof(rule CFGExit.method_exit_cases)
        assume "n' = NewExit"
        with n = NewExit show ?thesis by simp
      next
        fix a Q f p
        assume "n' = src a"
          and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
          and "knd a = Q↩⇘pf"
        hence "lift_get_proc get_proc Main (src a) = p"
          by -(rule CFGExit.get_proc_return)
        with CFGExit.get_proc_Exit lift_eq n' = src a n = NewExit
        have "p = Main" by simp
        with knd a = Q↩⇘pf have "knd a = Q↩⇘Mainf" by simp
        with lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a
        have False by(rule CFGExit.Main_no_return_source)
        thus ?thesis by simp
      qed
    next
      fix a Q f p
      assume "n = src a"
        and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
        and "knd a = Q↩⇘pf"
      then obtain x where "valid_edge x" and "src a = Node (sourcenode x)"
        and "kind x = Q↩⇘pf"
        by(fastforce elim:lift_valid_edge.cases)
      hence "method_exit (sourcenode x)" by(fastforce simp:method_exit_def)
      from method_exit2 show ?thesis
      proof(rule CFGExit.method_exit_cases)
        assume "n' = NewExit"
        from lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a
          knd a = Q↩⇘pf
        have "lift_get_proc get_proc Main (src a) = p"
          by -(rule CFGExit.get_proc_return)
        with CFGExit.get_proc_Exit lift_eq n = src a n' = NewExit
        have "p = Main" by simp
        with knd a = Q↩⇘pf have "knd a = Q↩⇘Mainf" by simp
        with lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a
        have False by(rule CFGExit.Main_no_return_source)
        thus ?thesis by simp
      next
        fix a' Q' f' p'
        assume "n' = src a'"
          and "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a'"
          and "knd a' = Q'↩⇘p'f'"
        then obtain x' where "valid_edge x'" and "src a' = Node (sourcenode x')"
          and "kind x' = Q'↩⇘p'f'"
          by(fastforce elim:lift_valid_edge.cases)
        hence "method_exit (sourcenode x')" by(fastforce simp:method_exit_def)
        with method_exit (sourcenode x) lift_eq n = src a n' = src a'
          src a = Node (sourcenode x) src a' = Node (sourcenode x')
        have "sourcenode x = sourcenode x'" by(fastforce intro:method_exit_unique)
        with src a = Node (sourcenode x) src a' = Node (sourcenode x')
          n = src a n' = src a'
        show ?thesis by simp
      qed
    qed
  qed
qed


lemma lift_SDG:
  assumes SDG:"SDG sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and inner:"CFGExit.inner_node sourcenode targetnode valid_edge Entry Exit nx"
  shows "SDG src trg knd
  (lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit) NewEntry
  (lift_get_proc get_proc Main) 
  (lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind) 
  procs Main NewExit (lift_Def Def Entry Exit H L) (lift_Use Use Entry Exit H L)
  (lift_ParamDefs ParamDefs) (lift_ParamUses ParamUses)"
proof -
  interpret SDG sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule SDG)
  have wf:"CFGExit_wf sourcenode targetnode kind valid_edge Entry get_proc
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
    by(unfold_locales)
  have pd:"Postdomination sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit"
    by(unfold_locales)
  interpret wf':CFGExit_wf src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main"
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
    procs Main NewExit "lift_Def Def Entry Exit H L" "lift_Use Use Entry Exit H L"
    "lift_ParamDefs ParamDefs" "lift_ParamUses ParamUses"
    by(fastforce intro:lift_CFGExit_wf wf pd)
  interpret pd':Postdomination src trg knd
    "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit" NewEntry
    "lift_get_proc get_proc Main"
    "lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind" 
    procs Main NewExit
    by(fastforce intro:lift_Postdomination wf pd inner)
  show ?thesis by(unfold_locales)
qed


subsubsection ‹Low-deterministic security via the lifted graph›

lemma Lift_NonInterferenceGraph:
  fixes valid_edge and sourcenode and targetnode and kind and Entry and Exit
  and get_proc and get_return_edges and procs and Main
  and Def and Use and ParamDefs and ParamUses and H and L
  defines lve:"lve  lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit"
  and lget_proc:"lget_proc  lift_get_proc get_proc Main"
  and lget_return_edges:"lget_return_edges  
  lift_get_return_edges get_return_edges valid_edge sourcenode targetnode kind"
  and lDef:"lDef  lift_Def Def Entry Exit H L" 
  and lUse:"lUse  lift_Use Use Entry Exit H L"
  and lParamDefs:"lParamDefs  lift_ParamDefs ParamDefs"
  and lParamUses:"lParamUses  lift_ParamUses ParamUses"
  assumes SDG:"SDG sourcenode targetnode kind valid_edge Entry get_proc 
  get_return_edges procs Main Exit Def Use ParamDefs ParamUses"
  and inner:"CFGExit.inner_node sourcenode targetnode valid_edge Entry Exit nx"
  and "H  L = {}" and "H  L = UNIV"
  shows "NonInterferenceInterGraph src trg knd lve NewEntry lget_proc 
  lget_return_edges procs Main NewExit lDef lUse lParamDefs lParamUses H L 
  (Node Entry) (Node Exit)"
proof -
  interpret SDG sourcenode targetnode kind valid_edge Entry get_proc 
    get_return_edges procs Main Exit Def Use ParamDefs ParamUses
    by(rule SDG)
  interpret SDG':SDG src trg knd lve NewEntry lget_proc lget_return_edges
    procs Main NewExit lDef lUse lParamDefs lParamUses
    by(fastforce intro:lift_SDG SDG inner simp:lve lget_proc lget_return_edges lDef
                      lUse lParamDefs lParamUses)
  show ?thesis
  proof
    fix a assume "lve a" and "src a = NewEntry"
    thus "trg a = NewExit  trg a = Node Entry"
      by(fastforce elim:lift_valid_edge.cases simp:lve)
  next
    show "a. lve a  src a = NewEntry  trg a = Node Entry  knd a = (λs. True)"
      by(fastforce intro:lve_Entry_edge simp:lve)
  next
    fix a assume "lve a" and "trg a = Node Entry"
    from lve a 
    have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      by(simp add:lve)
    from this trg a = Node Entry
    show "src a = NewEntry"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) 
        trg e = Node Entry
      have "targetnode a = Entry" by simp
      with valid_edge a have False by(rule Entry_target)
      thus ?case by simp
    qed simp_all
  next
    fix a assume "lve a" and "trg a = NewExit"
    thus "src a = NewEntry  src a = Node Exit"
      by(fastforce elim:lift_valid_edge.cases simp:lve)
  next
    show "a. lve a  src a = Node Exit  trg a = NewExit  knd a = (λs. True)"
      by(fastforce intro:lve_Exit_edge simp:lve)
  next
    fix a assume "lve a" and "src a = Node Exit"
    from lve a 
    have "lift_valid_edge valid_edge sourcenode targetnode kind Entry Exit a"
      by(simp add:lve)
    from this src a = Node Exit
    show "trg a = NewExit"
    proof(induct rule:lift_valid_edge.induct)
      case (lve_edge a e)
      from e = (Node (sourcenode a), kind a, Node (targetnode a)) 
        src e = Node Exit
      have "sourcenode a = Exit" by simp
      with valid_edge a have False by(rule Exit_source)
      thus ?case by simp
    qed simp_all
  next
    from lDef show "lDef (Node Entry) = H"
      by(fastforce elim:lift_Def_set.cases intro:lift_Def_High)
  next
    from Entry_noteq_Exit lUse show "lUse (Node Entry) = H"
      by(fastforce elim:lift_Use_set.cases intro:lift_Use_High)
  next
    from Entry_noteq_Exit lUse show "lUse (Node Exit) = L"
      by(fastforce elim:lift_Use_set.cases intro:lift_Use_Low)
  next
    from H  L = {} show "H  L = {}" .
  next
    from H  L = UNIV show "H  L = UNIV" .
  qed
qed

end