Theory AdditionalLemmas

section ‹Lemmas for the control dependences›

theory AdditionalLemmas imports WellFormed
begin

subsection ‹Paths to @{term "(_Exit_)"} and from @{term "(_Entry_)"} exist›

abbreviation path :: "cmd ⇒ w_node ⇒ w_edge list ⇒ w_node ⇒ bool" 
(‹_ ⊢ _ -_→* _›)
  where "prog ⊢ n -as→* n' ≡ CFG.path sourcenode targetnode (valid_edge prog) 
    n as n'"

definition label_incrs :: "w_edge list ⇒ nat ⇒ w_edge list" (‹_ ⊕s _› 60)
  where "as ⊕s i ≡ map (λ(n,et,n'). (n ⊕ i,et,n' ⊕ i)) as"


lemma path_SeqFirst:
  "prog ⊢ n -as→* (_ l _) ⟹ prog;;c2 ⊢ n -as→* (_ l _)"
proof(induct n as "(_ l _)" arbitrary:l rule:While_CFG.path.induct)
  case empty_path
  from ‹CFG.valid_node sourcenode targetnode (valid_edge prog) (_ l _)›
  show ?case
    apply -
    apply(rule While_CFG.empty_path)
    apply(auto simp:While_CFG.valid_node_def valid_edge_def)
    by(case_tac b,auto dest:WCFG_SeqFirst WCFG_SeqConnect)
next
  case (Cons_path n'' as a n)
  note IH = ‹prog;; c2 ⊢ n'' -as→* (_ l _)›
  from ‹prog ⊢ n'' -as→* (_ l _)› have "n'' ≠ (_Exit_)"
    by fastforce
  with ‹valid_edge prog a› ‹sourcenode a = n› ‹targetnode a = n''›
  have "prog;;c2 ⊢ n -kind a→ n''" by(simp add:valid_edge_def WCFG_SeqFirst)
  with IH ‹prog;;c2 ⊢ n -kind a→ n''› ‹sourcenode a = n› ‹targetnode a = n''› show ?case
    by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
qed


lemma path_SeqSecond:
  "⟦prog ⊢ n -as→* n'; n ≠ (_Entry_); as ≠ []⟧ 
  ⟹ c1;;prog ⊢ n ⊕ #:c1 -as ⊕s #:c1→* n' ⊕ #:c1"
proof(induct rule:While_CFG.path.induct)
  case (Cons_path n'' as n' a n)
  note IH = ‹ ⟦n'' ≠ (_Entry_); as ≠ []⟧ 
    ⟹ c1;;prog ⊢ n'' ⊕ #:c1 -as ⊕s #:c1→* n' ⊕ #:c1›
  from ‹valid_edge prog a› ‹sourcenode a = n› ‹targetnode a = n''› ‹n ≠ (_Entry_)›
  have "c1;;prog ⊢ n ⊕ #:c1 -kind a→ n'' ⊕ #:c1"
    by(simp add:valid_edge_def WCFG_SeqSecond)
  from ‹sourcenode a = n› ‹targetnode a = n''› ‹valid_edge prog a›
  have "[(n,kind a,n'')] ⊕s #:c1 = [a] ⊕s #:c1"
    by(cases a,simp add:label_incrs_def valid_edge_def)
  show ?case
  proof(cases "as = []")
    case True
    with ‹prog ⊢ n'' -as→* n'› have [simp]:"n'' = n'" by(auto elim:While_CFG.cases)
    with ‹c1;;prog ⊢ n ⊕ #:c1 -kind a→ n'' ⊕ #:c1›
    have "c1;;prog ⊢ n ⊕ #:c1 -[(n,kind a,n')] ⊕s #:c1→* n' ⊕ #:c1"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                  simp:label_incrs_def While_CFG.valid_node_def valid_edge_def)
    with True ‹[(n,kind a,n'')] ⊕s #:c1 = [a] ⊕s #:c1› show ?thesis by simp
  next
    case False
    from ‹valid_edge prog a› ‹targetnode a = n''› have "n'' ≠ (_Entry_)"
      by(cases n'',auto simp:valid_edge_def)
    from IH[OF this False] 
    have "c1;;prog ⊢ n'' ⊕ #:c1 -as ⊕s #:c1→* n' ⊕ #:c1" .
    with ‹c1;;prog ⊢ n ⊕ #:c1 -kind a→ n'' ⊕ #:c1› ‹sourcenode a = n›
      ‹targetnode a = n''› ‹[(n,kind a,n'')] ⊕s #:c1 = [a] ⊕s #:c1› show ?thesis
      apply(cases a)
      apply(simp add:label_incrs_def)
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
  qed
qed simp


lemma path_CondTrue:
  "prog ⊢ (_ l _) -as→* n' 
  ⟹ if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -as ⊕s 1→* n' ⊕ 1"
proof(induct "(_ l _)" as n' arbitrary:l rule:While_CFG.path.induct)
  case empty_path
  from ‹CFG.valid_node sourcenode targetnode (valid_edge prog) (_ l _)› 
    WCFG_CondTrue[of b prog c2]
  have "CFG.valid_node sourcenode targetnode (valid_edge (if (b) prog else c2)) 
    ((_ l _) ⊕ 1)"
    apply(auto simp:While_CFG.valid_node_def valid_edge_def)
    apply(rotate_tac 1,drule WCFG_CondThen,simp,fastforce)
    apply(case_tac a) apply auto
     apply(rotate_tac 1,drule WCFG_CondThen,simp,fastforce)
    by(rotate_tac 1,drule WCFG_EntryD,auto)
  then show ?case
    by(fastforce intro:While_CFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as n' a)
  note IH = ‹⋀l. n'' = (_ l _) 
    ⟹ if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -as ⊕s 1→* n' ⊕ 1›
  from ‹valid_edge prog a› ‹sourcenode a = (_ l _)›  ‹targetnode a = n''›
  have "if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -kind a→ n'' ⊕ 1"
    by -(rule WCFG_CondThen,simp_all add:valid_edge_def)
  from ‹sourcenode a = (_ l _)› ‹targetnode a = n''› ‹valid_edge prog a›
  have "[((_ l _),kind a,n'')] ⊕s 1 = [a] ⊕s 1"
    by(cases a,simp add:label_incrs_def valid_edge_def)
  show ?case
  proof(cases n'')
    case (Node l')
    from IH[OF this] have "if (b) prog else c2 ⊢ (_ l' _) ⊕ 1 -as ⊕s 1→* n' ⊕ 1" .
    with ‹if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -kind a→ n'' ⊕ 1› Node
    have "if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -((_ l _) ⊕ 1,kind a,n'' ⊕ 1)#(as ⊕s 1)→* n' ⊕ 1"
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def valid_node_def)
    with ‹[((_ l _),kind a,n'')] ⊕s 1 = [a] ⊕s 1› 
    have "if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -a#as ⊕s 1→* n' ⊕ 1"
      by(simp add:label_incrs_def)
    thus ?thesis by simp
  next
    case Entry
    with ‹valid_edge prog a› ‹targetnode a = n''› have False by fastforce
    thus ?thesis by simp
  next
    case Exit
    with ‹prog ⊢ n'' -as→* n'› have "n' = (_Exit_)" and "as = []"
      by(auto dest:While_CFGExit.path_Exit_source)
    from ‹if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -kind a→ n'' ⊕ 1› 
    have "if (b) prog else c2 ⊢ (_ l _) ⊕ 1 -[((_ l _) ⊕ 1,kind a,n'' ⊕ 1)]→* n'' ⊕ 1"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path 
                  simp:While_CFG.valid_node_def valid_edge_def)
    with Exit ‹[((_ l _),kind a,n'')] ⊕s 1 = [a] ⊕s 1›  ‹n' = (_Exit_)› ‹as = []›
    show ?thesis by(fastforce simp:label_incrs_def)
  qed
qed


lemma path_CondFalse:
  "prog ⊢ (_ l _) -as→* n'
  ⟹ if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) -as ⊕s (#:c1 + 1)→* n' ⊕ (#:c1 + 1)"
proof(induct "(_ l _)" as n' arbitrary:l rule:While_CFG.path.induct)
  case empty_path
  from ‹CFG.valid_node sourcenode targetnode (valid_edge prog) (_ l _)›
    WCFG_CondFalse[of b c1 prog]
  have "CFG.valid_node sourcenode targetnode (valid_edge (if (b) c1 else prog))
    ((_ l _) ⊕ #:c1 + 1)"
    apply(auto simp:While_CFG.valid_node_def valid_edge_def)
    apply(rotate_tac 1,drule WCFG_CondElse,simp,fastforce)
    apply(case_tac a) apply auto
     apply(rotate_tac 1,drule WCFG_CondElse,simp,fastforce)
    by(rotate_tac 1,drule WCFG_EntryD,auto)
  thus ?case by(fastforce intro:While_CFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as n' a)
  note IH = ‹⋀l. n'' = (_ l _) ⟹ if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) 
                                               -as ⊕s (#:c1 + 1)→* n' ⊕ (#:c1 + 1)›
  from ‹valid_edge prog a› ‹sourcenode a = (_ l _)›  ‹targetnode a = n''›
  have "if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) -kind a→ n'' ⊕ (#:c1 + 1)"
    by -(rule WCFG_CondElse,simp_all add:valid_edge_def)
  from ‹sourcenode a = (_ l _)› ‹targetnode a = n''› ‹valid_edge prog a›
  have "[((_ l _),kind a,n'')] ⊕s (#:c1 + 1) = [a] ⊕s (#:c1 + 1)"
    by(cases a,simp add:label_incrs_def valid_edge_def)
  show ?case
  proof(cases n'')
    case (Node l')
    from IH[OF this] have "if (b) c1 else prog ⊢ (_ l' _) ⊕ (#:c1 + 1) 
                                             -as ⊕s (#:c1 + 1)→* n' ⊕ (#:c1 + 1)" .
    with ‹if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) -kind a→ n'' ⊕ (#:c1 + 1)› Node
    have "if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) 
      -((_ l _) ⊕ (#:c1 + 1),kind a,n'' ⊕ (#:c1 + 1))#(as ⊕s (#:c1 + 1))→* 
      n' ⊕ (#:c1 + 1)"
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def valid_node_def)
    with ‹[((_ l _),kind a,n'')] ⊕s (#:c1 + 1) = [a] ⊕s (#:c1 + 1)› Node
    have "if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) -a#as ⊕s (#:c1 + 1)→* 
                                n' ⊕ (#:c1 + 1)"
      by(simp add:label_incrs_def)
    thus ?thesis by simp
  next
    case Entry
    with ‹valid_edge prog a› ‹targetnode a = n''› have False by fastforce
    thus ?thesis by simp
  next
    case Exit
    with ‹prog ⊢ n'' -as→* n'› have "n' = (_Exit_)" and "as = []"
      by(auto dest:While_CFGExit.path_Exit_source)
    from ‹if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) -kind a→ n'' ⊕ (#:c1 + 1)›
    have "if (b) c1 else prog ⊢ (_ l _) ⊕ (#:c1 + 1) 
          -[((_ l _) ⊕ (#:c1 + 1),kind a,n'' ⊕ (#:c1 + 1))]→* n'' ⊕ (#:c1 + 1)"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path 
                  simp:While_CFG.valid_node_def valid_edge_def)
    with Exit ‹[((_ l _),kind a,n'')] ⊕s (#:c1 + 1) = [a] ⊕s (#:c1 + 1)› ‹n' = (_Exit_)›
      ‹as = []› 
    show ?thesis by(fastforce simp:label_incrs_def)
  qed
qed

(*<*)declare add_2_eq_Suc' [simp del] One_nat_def [simp del](*>*)

lemma path_While:
  "prog ⊢ (_ l _) -as→* (_ l' _) 
  ⟹ while (b) prog ⊢ (_ l _) ⊕ 2 -as ⊕s 2→* (_ l' _) ⊕ 2"
proof(induct "(_ l _)" as "(_ l' _)" arbitrary:l l' rule:While_CFG.path.induct)
  case empty_path
  from ‹CFG.valid_node sourcenode targetnode (valid_edge prog) (_ l _)›
    WCFG_WhileTrue[of b prog]
  have "CFG.valid_node sourcenode targetnode (valid_edge (while (b) prog)) ((_ l _) ⊕ 2)"
    apply(auto simp:While_CFG.valid_node_def valid_edge_def)
     apply(case_tac ba) apply auto
      apply(rotate_tac 1,drule WCFG_WhileBody,auto)
     apply(rotate_tac 1,drule WCFG_WhileBodyExit,auto)
    apply(case_tac a) apply auto
     apply(rotate_tac 1,drule WCFG_WhileBody,auto)
    by(rotate_tac 1,drule WCFG_EntryD,auto)
  thus ?case by(fastforce intro:While_CFG.empty_path simp:label_incrs_def)
next
  case (Cons_path n'' as a)
  note IH = ‹⋀l. n'' = (_ l _)
    ⟹ while (b) prog ⊢ (_ l _) ⊕ 2 -as ⊕s 2→* (_ l' _) ⊕ 2›
   from ‹sourcenode a = (_ l _)› ‹targetnode a = n''› ‹valid_edge prog a›
  have "[((_ l _),kind a,n'')] ⊕s 2 = [a] ⊕s 2"
    by(cases a,simp add:label_incrs_def valid_edge_def)
  show ?case
  proof(cases n'')
    case (Node l'')
    with ‹valid_edge prog a› ‹sourcenode a = (_ l _)›  ‹targetnode a = n''›
    have "while (b) prog ⊢ (_ l _) ⊕ 2 -kind a→ n'' ⊕ 2"
      by -(rule WCFG_WhileBody,simp_all add:valid_edge_def)
    from IH[OF Node]
    have "while (b) prog ⊢ (_ l'' _) ⊕ 2 -as ⊕s 2→* (_ l' _) ⊕ 2" .
    with ‹while (b) prog ⊢ (_ l _) ⊕ 2 -kind a→ n'' ⊕ 2› Node
    have "while (b) prog ⊢ (_ l _) ⊕ 2 -((_ l _) ⊕ 2,kind a,n'' ⊕ 2)#(as ⊕s 2)→* (_ l' _) ⊕ 2"
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
    with ‹[((_ l _),kind a,n'')] ⊕s 2 = [a] ⊕s 2› show ?thesis by(simp add:label_incrs_def)
  next
    case Entry
    with ‹valid_edge prog a› ‹targetnode a = n''› have False by fastforce
    thus ?thesis by simp
  next
    case Exit
    with ‹prog ⊢ n'' -as→* (_ l' _)› have "(_ l' _) = (_Exit_)" and "as = []"
      by(auto dest:While_CFGExit.path_Exit_source)
    then have False by simp
    thus ?thesis by simp
  qed
qed



lemma inner_node_Entry_Exit_path: 
  "l < #:prog ⟹ (∃as. prog ⊢ (_ l _) -as→* (_Exit_)) ∧
                 (∃as. prog ⊢ (_Entry_) -as→* (_ l _))"
proof(induct prog arbitrary:l)
  case Skip
  from ‹l < #:Skip› have [simp]:"l = 0" by simp
  hence "Skip ⊢ (_ l _) -⇑id→ (_Exit_)" by(simp add:WCFG_Skip)
  hence "Skip ⊢ (_ l _) -[((_ l _),⇑id,(_Exit_))]→* (_Exit_)"
    by (fastforce intro: While_CFG.path.intros simp: valid_edge_def)
  have "Skip ⊢ (_Entry_) -(λs. True)√→ (_ l _)" by(simp add:WCFG_Entry)
  hence "Skip ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_ l _))]→* (_ l _)"
    by(fastforce intro:While_CFG.path.intros simp:valid_edge_def While_CFG.valid_node_def)
  with ‹Skip ⊢ (_ l _) -[((_ l _),⇑id,(_Exit_))]→* (_Exit_)› show ?case by fastforce
next
  case (LAss V e)
  from ‹l < #:V:=e› have "l = 0 ∨ l = 1" by auto
  thus ?case
  proof
    assume [simp]:"l = 0"
    hence "V:=e ⊢ (_Entry_) -(λs. True)√→ (_ l _)" by(simp add:WCFG_Entry)
    hence "V:=e ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_ l _))]→* (_ l _)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def While_CFG.valid_node_def)
    have "V:=e ⊢ (_1_) -⇑id→ (_Exit_)" by(rule WCFG_LAssSkip)
    hence "V:=e ⊢ (_1_) -[((_1_),⇑id,(_Exit_))]→* (_Exit_)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def)
    with WCFG_LAss have "V:=e ⊢ (_ l _) -
      [((_ l _),⇑(λs. s(V:=(interpret e s))),(_1_)),((_1_),⇑id,(_Exit_))]→*
      (_Exit_)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def)
    with ‹V:=e ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_ l _))]→* (_ l _)›
    show ?case by fastforce
  next
    assume [simp]:"l = 1"
    hence "V:=e ⊢ (_ l _) -⇑id→ (_Exit_)" by(simp add:WCFG_LAssSkip)
    hence "V:=e ⊢ (_ l _) -[((_ l _),⇑id,(_Exit_))]→* (_Exit_)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def)
    have "V:=e ⊢ (_0_) -⇑(λs. s(V:=(interpret e s)))→ (_ l _)"
      by(simp add:WCFG_LAss)
    hence "V:=e ⊢ (_0_) -[((_0_),⇑(λs. s(V:=(interpret e s))),(_ l _))]→* (_ l _)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def While_CFG.valid_node_def)
    with WCFG_Entry[of "V:=e"] have "V:=e ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_0_))
      ,((_0_),⇑(λs. s(V:=(interpret e s))),(_ l _))]→* (_ l _)"
      by(fastforce intro:While_CFG.path.intros simp:valid_edge_def)
    with ‹V:=e ⊢ (_ l _) -[((_ l _),⇑id,(_Exit_))]→* (_Exit_)› show ?case by fastforce
  qed
next
  case (Seq prog1 prog2)
  note IH1 = ‹⋀l. l < #:prog1 ⟹
  (∃as. prog1 ⊢ (_ l _) -as→* (_Exit_)) ∧ (∃as. prog1 ⊢ (_Entry_) -as→* (_ l _))›
  note IH2 = ‹⋀l. l < #:prog2 ⟹
  (∃as. prog2 ⊢ (_ l _) -as→* (_Exit_)) ∧ (∃as. prog2 ⊢ (_Entry_) -as→* (_ l _))›
  show ?case
  proof(cases "l < #:prog1")
    case True
    from IH1[OF True] obtain as as' where "prog1 ⊢ (_ l _) -as→* (_Exit_)"
      and "prog1 ⊢ (_Entry_) -as'→* (_ l _)" by blast
    from ‹prog1 ⊢ (_Entry_) -as'→* (_ l _)›
    have "prog1;;prog2 ⊢ (_Entry_) -as'→* (_ l _)"
      by(fastforce intro:path_SeqFirst)
    from ‹prog1 ⊢ (_ l _) -as→* (_Exit_)›
    obtain asx ax where "prog1 ⊢ (_ l _) -asx@[ax]→* (_Exit_)"
      by(induct rule:rev_induct,auto elim:While_CFG.path.cases)
    hence "prog1 ⊢ (_ l _) -asx→* sourcenode ax"
      and "valid_edge prog1 ax" and "(_Exit_) = targetnode ax"
      by(auto intro:While_CFG.path_split_snoc)
    from ‹prog1 ⊢ (_ l _) -asx→* sourcenode ax› ‹valid_edge prog1 ax›
    obtain lx where [simp]:"sourcenode ax = (_ lx _)"
      by(cases "sourcenode ax") auto
    with ‹prog1 ⊢ (_ l _) -asx→* sourcenode ax› 
    have "prog1;;prog2 ⊢ (_ l _) -asx→* sourcenode ax"
      by(fastforce intro:path_SeqFirst)
    from ‹valid_edge prog1 ax› ‹(_Exit_) = targetnode ax›
    have "prog1;;prog2 ⊢ sourcenode ax -kind ax→ (_0_) ⊕ #:prog1"
      by(fastforce intro:WCFG_SeqConnect simp:valid_edge_def)
    hence "prog1;;prog2 ⊢ sourcenode ax -[(sourcenode ax,kind ax,(_0_) ⊕ #:prog1)]→*
                          (_0_) ⊕ #:prog1"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path 
                  simp:While_CFG.valid_node_def valid_edge_def)
    with ‹prog1;;prog2 ⊢ (_ l _) -asx→* sourcenode ax›
    have "prog1;;prog2 ⊢ (_ l _) -asx@[(sourcenode ax,kind ax,(_0_) ⊕ #:prog1)]→*
                         (_0_) ⊕ #:prog1"
      by(fastforce intro:While_CFG.path_Append)
    from IH2[of "0"] obtain as'' where "prog2 ⊢ (_ 0 _) -as''→* (_Exit_)" by blast
    hence "prog1;;prog2 ⊢ (_0_) ⊕ #:prog1 -as'' ⊕s #:prog1→* (_Exit_) ⊕ #:prog1"
      by(fastforce intro!:path_SeqSecond elim:While_CFG.path.cases)
    hence "prog1;;prog2 ⊢ (_0_) ⊕ #:prog1 -as'' ⊕s #:prog1→* (_Exit_)"
      by simp
    with ‹prog1;;prog2 ⊢ (_ l _) -asx@[(sourcenode ax,kind ax,(_0_) ⊕ #:prog1)]→*
                         (_0_) ⊕ #:prog1›
    have "prog1;;prog2 ⊢ (_ l _) -(asx@[(sourcenode ax,kind ax,(_0_) ⊕ #:prog1)])@
                                  (as'' ⊕s #:prog1)→* (_Exit_)"
      by(fastforce intro:While_CFG.path_Append)
    with ‹prog1;;prog2 ⊢ (_Entry_) -as'→* (_ l _)› show ?thesis by blast
  next
    case False
    hence "#:prog1 ≤ l" by simp
    then obtain l' where [simp]:"l = l' + #:prog1" and "l' = l - #:prog1" by simp
    from ‹l < #:prog1;; prog2› have "l' < #:prog2" by simp
    from IH2[OF this] obtain as as' where "prog2 ⊢ (_ l' _) -as→* (_Exit_)"
      and "prog2 ⊢ (_Entry_) -as'→* (_ l' _)" by blast
    from ‹prog2 ⊢ (_ l' _) -as→* (_Exit_)› 
    have "prog1;;prog2 ⊢ (_ l' _) ⊕ #:prog1 -as ⊕s #:prog1→* (_Exit_) ⊕ #:prog1"
      by(fastforce intro!:path_SeqSecond elim:While_CFG.path.cases)
    hence "prog1;;prog2 ⊢ (_ l _) -as ⊕s #:prog1→* (_Exit_)"
      by simp
    from IH1[of 0] obtain as'' where "prog1 ⊢ (_0_) -as''→* (_Exit_)" by blast
    then obtain ax asx where "prog1 ⊢ (_0_) -asx@[ax]→* (_Exit_)"
      by(induct rule:rev_induct,auto elim:While_CFG.path.cases)
    hence "prog1 ⊢ (_0_) -asx→* sourcenode ax" and "valid_edge prog1 ax"
      and "(_Exit_) = targetnode ax" by(auto intro:While_CFG.path_split_snoc)
    from WCFG_Entry ‹prog1 ⊢ (_0_) -asx→* sourcenode ax›
    have "prog1 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#asx→* sourcenode ax"
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def valid_node_def)
    from ‹prog1 ⊢ (_0_) -asx→* sourcenode ax› ‹valid_edge prog1 ax›
    obtain lx where [simp]:"sourcenode ax = (_ lx _)"
      by(cases "sourcenode ax") auto
    with ‹prog1 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#asx→* sourcenode ax›
    have "prog1;;prog2 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#asx→* 
                         sourcenode ax"
      by(fastforce intro:path_SeqFirst)
    from ‹prog2 ⊢ (_Entry_) -as'→* (_ l' _)› obtain ax' asx' 
      where "prog2 ⊢ (_Entry_) -ax'#asx'→* (_ l' _)" 
      by(cases as',auto elim:While_CFG.path.cases)
    hence "(_Entry_) = sourcenode ax'" and "valid_edge prog2 ax'"
      and "prog2 ⊢ targetnode ax' -asx'→* (_ l' _)"
      by(auto intro:While_CFG.path_split_Cons)
    hence "targetnode ax' = (_0_)" by(fastforce dest:WCFG_EntryD simp:valid_edge_def)
    from ‹valid_edge prog1 ax› ‹(_Exit_) = targetnode ax›
    have "prog1;;prog2 ⊢ sourcenode ax -kind ax→ (_0_) ⊕ #:prog1"
      by(fastforce intro:WCFG_SeqConnect simp:valid_edge_def)
    have "∃as. prog1;;prog2 ⊢ sourcenode ax -as→* (_ l _)"
    proof(cases "asx' = []")
      case True
      with ‹prog2 ⊢ targetnode ax' -asx'→* (_ l' _)› ‹targetnode ax' = (_0_)›
      have "l' = 0" by(auto elim:While_CFG.path.cases)
      with ‹prog1;;prog2 ⊢ sourcenode ax -kind ax→ (_0_) ⊕ #:prog1›     
      have "prog1;;prog2 ⊢ sourcenode ax -[(sourcenode ax,kind ax,(_ l _))]→* 
                           (_ l _)"
        by(auto intro!:While_CFG.path.intros 
                    simp:While_CFG.valid_node_def valid_edge_def,blast)
      thus ?thesis by blast
    next
      case False
      with ‹prog2 ⊢ targetnode ax' -asx'→* (_ l' _)› ‹targetnode ax' = (_0_)›
      have "prog1;;prog2 ⊢ (_0_) ⊕ #:prog1 -asx' ⊕s #:prog1→* (_ l' _) ⊕ #:prog1"
        by(fastforce intro:path_SeqSecond)
      hence "prog1;;prog2 ⊢ (_0_) ⊕ #:prog1 -asx' ⊕s #:prog1→* (_ l _)" by simp
      with ‹prog1;;prog2 ⊢ sourcenode ax -kind ax→ (_0_) ⊕ #:prog1›
      have "prog1;;prog2 ⊢ sourcenode ax -(sourcenode ax,kind ax,(_0_) ⊕ #:prog1)#
                                          (asx' ⊕s #:prog1)→* (_ l _)"
        by(fastforce intro: While_CFG.Cons_path simp:valid_node_def valid_edge_def)
      thus ?thesis by blast
    qed
    then obtain asx'' where "prog1;;prog2 ⊢ sourcenode ax -asx''→* (_ l _)" by blast
    with ‹prog1;;prog2 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#asx→* 
                         sourcenode ax›
    have "prog1;;prog2 ⊢ (_Entry_) -(((_Entry_),(λs. True)√,(_0_))#asx)@asx''→* 
                         (_ l _)"
      by(rule While_CFG.path_Append)
    with ‹prog1;;prog2 ⊢ (_ l _) -as ⊕s #:prog1→* (_Exit_)›
    show ?thesis by blast
  qed
next
  case (Cond b prog1 prog2)
  note IH1 = ‹⋀l. l < #:prog1 ⟹
  (∃as. prog1 ⊢ (_ l _) -as→* (_Exit_)) ∧ (∃as. prog1 ⊢ (_Entry_) -as→* (_ l _))›
  note IH2 = ‹⋀l. l < #:prog2 ⟹
  (∃as. prog2 ⊢ (_ l _) -as→* (_Exit_)) ∧ (∃as. prog2 ⊢ (_Entry_) -as→* (_ l _))›
  show ?case
  proof(cases "l = 0")
    case True
    from IH1[of 0] obtain as where "prog1 ⊢ (_0_) -as→* (_Exit_)" by blast
    hence "if (b) prog1 else prog2 ⊢ (_0_) ⊕ 1 -as ⊕s 1→* (_Exit_) ⊕ 1"
      by(fastforce intro:path_CondTrue)
    with WCFG_CondTrue[of b prog1 prog2] have "if (b) prog1 else prog2 ⊢ 
      (_0_) -((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 1)#(as ⊕s 1)→* 
      (_Exit_) ⊕ 1"
      by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def valid_node_def)
    with True have "if (b) prog1 else prog2 ⊢ 
      (_ l _) -((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 1)#(as ⊕s 1)→*
      (_Exit_)" by simp
    moreover
    from WCFG_Entry[of "if (b) prog1 else prog2"] True
    have "if (b) prog1 else prog2 ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_0_))]→* 
                                    (_ l _)"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                  simp:While_CFG.valid_node_def valid_edge_def)
    ultimately show ?thesis by blast
  next
    case False
    hence "0 < l" by simp
    then obtain l' where [simp]:"l = l' + 1" and "l' = l - 1" by simp
    show ?thesis
    proof(cases "l' < #:prog1")
      case True
      from IH1[OF this] obtain as as' where "prog1 ⊢ (_ l' _) -as→* (_Exit_)"
        and "prog1 ⊢ (_Entry_) -as'→* (_ l' _)" by blast
      from ‹prog1 ⊢ (_ l' _) -as→* (_Exit_)›
      have "if (b) prog1 else prog2 ⊢ (_ l' _) ⊕ 1 -as ⊕s 1→* (_Exit_) ⊕ 1"
        by(fastforce intro:path_CondTrue)
      hence "if (b) prog1 else prog2 ⊢ (_ l _) -as ⊕s 1→* (_Exit_)"
        by simp
      from ‹prog1 ⊢ (_Entry_) -as'→* (_ l' _)› obtain ax asx
        where "prog1 ⊢ (_Entry_) -ax#asx→* (_ l' _)"
        by(cases as',auto elim:While_CFG.cases)
      hence "(_Entry_) = sourcenode ax" and "valid_edge prog1 ax"
        and "prog1 ⊢ targetnode ax -asx→* (_ l' _)"
        by(auto intro:While_CFG.path_split_Cons)
      hence "targetnode ax = (_0_)" by(fastforce dest:WCFG_EntryD simp:valid_edge_def)
      with ‹prog1 ⊢ targetnode ax -asx→* (_ l' _)›
      have "if (b) prog1 else prog2 ⊢ (_0_) ⊕ 1 -asx ⊕s 1→* (_ l' _) ⊕ 1"
        by(fastforce intro:path_CondTrue)
      with WCFG_CondTrue[of b prog1 prog2]
      have "if (b) prog1 else prog2 ⊢ (_0_) 
        -((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 1)#(asx ⊕s 1)→* 
         (_ l' _) ⊕ 1"
        by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
      with WCFG_Entry[of "if (b) prog1 else prog2"]
      have "if (b) prog1 else prog2 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#
        ((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 1)#(asx ⊕s 1)→* 
         (_ l' _) ⊕ 1"
        by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
      with ‹if (b) prog1 else prog2 ⊢ (_ l _) -as ⊕s 1→* (_Exit_)›
      show ?thesis by simp blast
    next
      case False
      hence "#:prog1 ≤ l'" by simp
      then obtain l'' where [simp]:"l' = l'' + #:prog1" and "l'' = l' - #:prog1"
        by simp
      from  ‹l < #:(if (b) prog1 else prog2)› 
      have "l'' < #:prog2" by simp
      from IH2[OF this] obtain as as' where "prog2 ⊢ (_ l'' _) -as→* (_Exit_)"
        and "prog2 ⊢ (_Entry_) -as'→* (_ l'' _)" by blast
      from ‹prog2 ⊢ (_ l'' _) -as→* (_Exit_)›
      have "if (b) prog1 else prog2 ⊢ (_ l'' _) ⊕ (#:prog1 + 1) 
        -as ⊕s (#:prog1 + 1)→* (_Exit_) ⊕ (#:prog1 + 1)"
        by(fastforce intro:path_CondFalse)
      hence "if (b) prog1 else prog2 ⊢ (_ l _) -as ⊕s (#:prog1 + 1)→* (_Exit_)"
        by(simp add:add.assoc)
      from ‹prog2 ⊢ (_Entry_) -as'→* (_ l'' _)› obtain ax asx
        where "prog2 ⊢ (_Entry_) -ax#asx→* (_ l'' _)"
        by(cases as',auto elim:While_CFG.cases)
      hence "(_Entry_) = sourcenode ax" and "valid_edge prog2 ax"
        and "prog2 ⊢ targetnode ax -asx→* (_ l'' _)"
        by(auto intro:While_CFG.path_split_Cons)
      hence "targetnode ax = (_0_)" by(fastforce dest:WCFG_EntryD simp:valid_edge_def)
      with ‹prog2 ⊢ targetnode ax -asx→* (_ l'' _)›
      have "if (b) prog1 else prog2 ⊢ (_0_) ⊕ (#:prog1 + 1) -asx ⊕s (#:prog1 + 1)→*
        (_ l'' _) ⊕ (#:prog1 + 1)"
        by(fastforce intro:path_CondFalse)
      with WCFG_CondFalse[of b prog1 prog2]
      have "if (b) prog1 else prog2 ⊢ (_0_) 
        -((_0_),(λs. interpret b s = Some false)√,(_0_) ⊕ (#:prog1 + 1))#
        (asx ⊕s  (#:prog1 + 1))→* (_ l'' _) ⊕  (#:prog1 + 1)"
        by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
      with WCFG_Entry[of "if (b) prog1 else prog2"]
      have "if (b) prog1 else prog2 ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#
        ((_0_),(λs. interpret b s = Some false)√,(_0_) ⊕ (#:prog1 + 1))#
        (asx ⊕s (#:prog1 + 1))→* (_ l'' _) ⊕ (#:prog1 + 1)"
        by(fastforce intro:While_CFG.Cons_path simp:valid_edge_def)
      with 
        ‹if (b) prog1 else prog2 ⊢ (_ l _) -as ⊕s (#:prog1 + 1)→* (_Exit_)›
      show ?thesis by(simp add:add.assoc,blast)
    qed
  qed
next
  case (While b prog')
  note IH = ‹⋀l. l < #:prog' ⟹
   (∃as. prog' ⊢ (_ l _) -as→* (_Exit_)) ∧ (∃as. prog' ⊢ (_Entry_) -as→* (_ l _))›
  show ?case
  proof(cases "l < 1")
    case True
    from WCFG_Entry[of "while (b) prog'"]
    have "while (b) prog' ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_0_))]→* (_0_)"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                  simp:While_CFG.valid_node_def valid_edge_def)
    from WCFG_WhileFalseSkip[of b prog']
    have "while (b) prog' ⊢ (_1_) -[((_1_),⇑id,(_Exit_))]→* (_Exit_)"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                  simp:valid_node_def valid_edge_def)
    with WCFG_WhileFalse[of b prog']
    have "while (b) prog' ⊢ (_0_) -((_0_),(λs. interpret b s = Some false)√,(_1_))#
      [((_1_),⇑id,(_Exit_))]→* (_Exit_)"
      by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                  simp:valid_node_def valid_edge_def)
    with ‹while (b) prog' ⊢ (_Entry_) -[((_Entry_),(λs. True)√,(_0_))]→* (_0_)› True
    show ?thesis by simp blast
  next
    case False
    hence "1 ≤ l" by simp
    thus ?thesis
    proof(cases "l < 2")
      case True
      with ‹1 ≤ l› have [simp]:"l = 1" by simp
      from WCFG_WhileFalseSkip[of b prog']
      have "while (b) prog' ⊢ (_1_) -[((_1_),⇑id,(_Exit_))]→* (_Exit_)"
        by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                    simp:valid_node_def valid_edge_def)
      from WCFG_WhileFalse[of b prog']
      have "while (b) prog' ⊢ (_0_) 
        -[((_0_),(λs. interpret b s = Some false)√,(_1_))]→* (_1_)"
        by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                    simp:While_CFG.valid_node_def valid_edge_def)
      with WCFG_Entry[of "while (b) prog'"]
      have "while (b) prog' ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#
        [((_0_),(λs. interpret b s = Some false)√,(_1_))]→* (_1_)"
        by(fastforce intro:While_CFG.Cons_path simp:valid_node_def valid_edge_def)
      with ‹while (b) prog' ⊢ (_1_) -[((_1_),⇑id,(_Exit_))]→* (_Exit_)› 
      show ?thesis by simp blast
    next
      case False
      with ‹1 ≤ l› have "2 ≤ l" by simp
      then obtain l' where [simp]:"l = l' + 2" and "l' = l - 2" 
        by(simp del:add_2_eq_Suc')
      from ‹l < #:while (b) prog'› have "l' < #:prog'" by simp
      from IH[OF this] obtain as as' where "prog' ⊢ (_ l' _) -as→* (_Exit_)"
        and "prog' ⊢ (_Entry_) -as'→* (_ l' _)" by blast
      from ‹prog' ⊢ (_ l' _) -as→* (_Exit_)› obtain ax asx where
        "prog' ⊢ (_ l' _) -asx@[ax]→* (_Exit_)"
        by(induct as rule:rev_induct,auto elim:While_CFG.cases)
      hence "prog' ⊢ (_ l' _) -asx→* sourcenode ax" and "valid_edge prog' ax"
        and "(_Exit_) = targetnode ax"
        by(auto intro:While_CFG.path_split_snoc)
      then obtain lx where "sourcenode ax = (_ lx _)"
        by(cases "sourcenode ax") auto
      with ‹prog' ⊢ (_ l' _) -asx→* sourcenode ax›
      have "while (b) prog' ⊢ (_ l' _) ⊕ 2 -asx ⊕s 2→* sourcenode ax ⊕ 2"
        by(fastforce intro:path_While simp del:label_incr.simps)
      from WCFG_WhileFalseSkip[of b prog']
      have "while (b) prog' ⊢ (_1_) -[((_1_),⇑id,(_Exit_))]→* (_Exit_)"
        by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                    simp:valid_node_def valid_edge_def)
      with WCFG_WhileFalse[of b prog']
      have "while (b) prog' ⊢ (_0_) -((_0_),(λs. interpret b s = Some false)√,(_1_))#
        [((_1_),⇑id,(_Exit_))]→* (_Exit_)"
        by(fastforce intro:While_CFG.Cons_path simp:valid_node_def valid_edge_def)
      with ‹valid_edge prog' ax› ‹(_Exit_) = targetnode ax› ‹sourcenode ax = (_ lx _)›
      have "while (b) prog' ⊢ sourcenode ax ⊕ 2 -(sourcenode ax ⊕ 2,kind ax,(_0_))#
        ((_0_),(λs. interpret b s = Some false)√,(_1_))#
        [((_1_),⇑id,(_Exit_))]→* (_Exit_)"
        by(fastforce intro:While_CFG.Cons_path dest:WCFG_WhileBodyExit
                    simp:valid_node_def valid_edge_def)
      with ‹while (b) prog' ⊢ (_ l' _) ⊕ 2 -asx ⊕s 2→* sourcenode ax ⊕ 2›
      have path:"while (b) prog' ⊢ (_ l' _) ⊕ 2 -(asx ⊕s 2)@
        ((sourcenode ax ⊕ 2,kind ax,(_0_))#
        ((_0_),(λs. interpret b s = Some false)√,(_1_))#
        [((_1_),⇑id,(_Exit_))])→* (_Exit_)"
        by(rule While_CFG.path_Append)
      from ‹prog' ⊢ (_Entry_) -as'→* (_ l' _)› obtain ax' asx'
        where "prog' ⊢ (_Entry_) -ax'#asx'→* (_ l' _)"
        by(cases as',auto elim:While_CFG.cases)
      hence "(_Entry_) = sourcenode ax'" and "valid_edge prog' ax'"
        and "prog' ⊢ targetnode ax' -asx'→* (_ l' _)"
        by(auto intro:While_CFG.path_split_Cons)
      hence "targetnode ax' = (_0_)" by(fastforce dest:WCFG_EntryD simp:valid_edge_def)
      with ‹prog' ⊢ targetnode ax' -asx'→* (_ l' _)›
      have "while (b) prog' ⊢ (_0_) ⊕ 2 -asx' ⊕s 2→* (_ l' _) ⊕ 2"
        by(fastforce intro:path_While)
      with WCFG_WhileTrue[of b prog']
      have "while (b) prog' ⊢ (_0_) 
        -((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 2)#(asx' ⊕s 2)→* 
        (_ l' _) ⊕ 2"
        by(fastforce intro:While_CFG.Cons_path simp:valid_node_def valid_edge_def)
      with WCFG_Entry[of "while (b) prog'"]
      have "while (b) prog' ⊢ (_Entry_) -((_Entry_),(λs. True)√,(_0_))#
        ((_0_),(λs. interpret b s = Some true)√,(_0_) ⊕ 2)#(asx' ⊕s 2)→* 
        (_ l' _) ⊕ 2"
        by(fastforce intro:While_CFG.Cons_path simp:valid_node_def valid_edge_def)
      with path show ?thesis by simp blast
    qed
  qed
qed

(*<*)declare add_2_eq_Suc' [simp] One_nat_def [simp](*>*)


lemma valid_node_Exit_path:
  assumes "valid_node prog n" shows "∃as. prog ⊢ n -as→* (_Exit_)"
proof(cases n)
  case (Node l)
  with ‹valid_node prog n› have "l < #:prog"
    by(fastforce dest:WCFG_sourcelabel_less_num_nodes WCFG_targetlabel_less_num_nodes
                simp:valid_node_def valid_edge_def)
  with Node show ?thesis by(fastforce dest:inner_node_Entry_Exit_path)
next
  case Entry
  from WCFG_Entry_Exit[of prog]
  have "prog ⊢ (_Entry_) -[((_Entry_),(λs. False)√,(_Exit_))]→* (_Exit_)"
    by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                simp:valid_node_def valid_edge_def)
  with Entry show ?thesis by blast
next
  case Exit
  with WCFG_Entry_Exit[of prog]
  have "prog ⊢ n -[]→* (_Exit_)"
    by(fastforce intro:While_CFG.empty_path simp:valid_node_def valid_edge_def)
  thus ?thesis by blast
qed


lemma valid_node_Entry_path:
  assumes "valid_node prog n" shows "∃as. prog ⊢ (_Entry_) -as→* n"
proof(cases n)
  case (Node l)
  with ‹valid_node prog n› have "l < #:prog"
    by(fastforce dest:WCFG_sourcelabel_less_num_nodes WCFG_targetlabel_less_num_nodes
                simp:valid_node_def valid_edge_def)
  with Node show ?thesis by(fastforce dest:inner_node_Entry_Exit_path)
next
  case Entry
  with WCFG_Entry_Exit[of prog]
  have "prog ⊢ (_Entry_) -[]→* n"
    by(fastforce intro:While_CFG.empty_path simp:valid_node_def valid_edge_def)
  thus ?thesis by blast
next
  case Exit
  from WCFG_Entry_Exit[of prog]
  have "prog ⊢ (_Entry_) -[((_Entry_),(λs. False)√,(_Exit_))]→* (_Exit_)"
    by(fastforce intro:While_CFG.Cons_path While_CFG.empty_path
                simp:valid_node_def valid_edge_def)
  with Exit show ?thesis by blast
qed


subsection ‹Some finiteness considerations›

lemma finite_labels:"finite {l. ∃c. labels prog l c}"
proof -
  have "finite {l::nat. l < #:prog}" by(fastforce intro:nat_seg_image_imp_finite)
  moreover have "{l. ∃c. labels prog l c} ⊆ {l::nat. l < #:prog}"
    by(fastforce intro:label_less_num_inner_nodes)
  ultimately show ?thesis by(auto intro:finite_subset)
qed


lemma finite_valid_nodes:"finite {n. valid_node prog n}"
proof -
  have "{n. ∃n' et. prog ⊢ n -et→ n'} ⊆ 
    insert (_Entry_) ((λl'. (_ l' _)) ` {l. ∃c. labels prog l c})"
    apply clarsimp
    apply(case_tac x,auto)
    by(fastforce dest:WCFG_sourcelabel_less_num_nodes less_num_inner_nodes_label)
  hence "finite {n. ∃n' et. prog ⊢ n -et→ n'}"
    by(auto intro:finite_subset finite_imageI finite_labels)
  have "{n'. ∃n et. prog ⊢ n -et→ n'} ⊆ 
    insert (_Exit_) ((λl'. (_ l' _)) ` {l. ∃c. labels prog l c})"
    apply clarsimp
    apply(case_tac x,auto)
    by(fastforce dest:WCFG_targetlabel_less_num_nodes less_num_inner_nodes_label)
  hence "finite {n'. ∃n et. prog ⊢ n -et→ n'}"
    by(auto intro:finite_subset finite_imageI finite_labels)
  have "{n. ∃nx et nx'. prog ⊢ nx -et→ nx' ∧ (n = nx ∨ n = nx')} =
    {n. ∃n' et. prog ⊢ n -et→ n'} Un {n'. ∃n et. prog ⊢ n -et→ n'}" by blast
  with ‹finite {n. ∃n' et. prog ⊢ n -et→ n'}› ‹finite {n'. ∃n et. prog ⊢ n -et→ n'}›
  have "finite {n. ∃nx et nx'. prog ⊢ nx -et→ nx' ∧ (n = nx ∨ n = nx')}"
    by fastforce
  thus ?thesis by(simp add:valid_node_def valid_edge_def)
qed

lemma finite_successors:
  "finite {n'. ∃a'. valid_edge prog a' ∧ sourcenode a' = n ∧ 
                    targetnode a' = n'}"
proof -
  have "{n'. ∃a'. valid_edge prog a' ∧ sourcenode a' = n ∧ 
                  targetnode a' = n'} ⊆ {n. valid_node prog n}"
    by(auto simp:valid_edge_def valid_node_def)
  thus ?thesis by(fastforce elim:finite_subset intro:finite_valid_nodes)
qed


end