Theory Strong_Late_Expansion_Law

(* 
   Title: The pi-calculus   
   Author/Maintainer: Jesper Bengtson (jebe.dk), 2012
*)
theory Strong_Late_Expansion_Law
  imports Strong_Late_Bisim_SC
begin

nominal_primrec summands :: "pi  pi set" where 
  "summands 𝟬 = {}"
| "summands (τ.(P)) = {τ.(P)}"
| "x  a  summands (a<x>.P) = {a<x>.P}"
| "summands (a{b}.P) = {a{b}.P}"
| "summands ([ab]P) = {}"
| "summands ([ab]P) = {}"
| "summands (P  Q) = (summands P)  (summands Q)"
| "summands (P  Q) = {}"
| "summands (x>P) = (if (a P'. a  x  P = a{x}.P') then ({x>P}) else {})"
| "summands (!P) = {}"
apply(auto simp add: fresh_singleton name_fresh_abs fresh_set_empty fresh_singleton pi.fresh)
apply(finite_guess)+
by(fresh_guess)+

lemma summandsInput[simp]:
  fixes a :: name
  and   x :: name
  and   P :: pi

  shows "summands (a<x>.P) = {a<x>.P}"
proof -
  obtain y where yineqa: "y  a" and yFreshP: "y  P"
    by(force intro: name_exists_fresh[of "(a, P)"] simp add: fresh_prod)
  from yFreshP have "a<x>.P = a<y>.([(x, y)]  P)" by(simp add: alphaInput)
  with yineqa show ?thesis by simp
qed

lemma finiteSummands:
  fixes P :: pi
  
  shows "finite(summands P)"
by(induct P rule: pi.induct) auto

lemma boundSummandDest[dest]:
  fixes x  :: name
  and   y  :: name
  and   P' :: pi
  and   P  :: pi

  assumes "x>x{y}.P'  summands P"
  
  shows False
using assms
by(induct P rule: pi.induct, auto simp add: if_split pi.inject name_abs_eq name_calc)

lemma summandFresh:
  fixes P :: pi
  and   Q :: pi
  and   x :: name

  assumes "P  summands Q"
  and     "x  Q"
  
  shows "x  P"
using assms
by(nominal_induct Q avoiding: P rule: pi.strong_induct, auto simp add: if_split)

nominal_primrec hnf :: "pi  bool" where
  "hnf 𝟬 = True"
| "hnf (τ.(P)) = True"
| "x  a  hnf (a<x>.P) = True"
| "hnf (a{b}.P) = True"
| "hnf ([ab]P) = False"
| "hnf ([ab]P) = False"
| "hnf (P  Q) = ((hnf P)  (hnf Q)  P  𝟬  Q  𝟬)"
| "hnf (P  Q) = False"
| "hnf (x>P) = (a P'. a  x  P = a{x}.P')"
| "hnf (!P) = False"
apply(auto simp add: fresh_bool)
apply(finite_guess)+
by(fresh_guess)+

lemma hnfInput[simp]:
  fixes a :: name
  and   x :: name
  and   P :: pi

  shows "hnf (a<x>.P)"
proof -
  obtain y where yineqa: "y  a" and yFreshP: "y  P"
    by(force intro: name_exists_fresh[of "(a, P)"] simp add: fresh_prod)
  from yFreshP have "a<x>.P = a<y>.([(x, y)]  P)" by(simp add: alphaInput)
  with yineqa show ?thesis by simp
qed

lemma summandTransition:
  fixes P  :: pi
  and   a  :: name
  and   x  :: name
  and   b  :: name
  and   P' :: pi

  assumes "hnf P"

  shows "P τ  P' = (τ.(P')  summands P)"
  and   "P a<x>  P' = (a<x>.P'  summands P)"
  and   "P a[b]  P' = (a{b}.P'  summands P)"
  and   "a  x  P ax>  P' = (x>a{x}.P'  summands P)"
proof -
  from assms show "P τ  P' = (τ.(P')  summands P)"
  proof(induct P rule: pi.induct)
    case PiNil
    show ?case by auto
  next
    case(Output a b P)
    show ?case by auto
  next
    case(Tau P)
    have "τ.(P) τ  P'  τ.(P')  summands (τ.(P))"
      by(auto elim: tauCases simp add: pi.inject residual.inject)
    moreover have "τ.(P')  summands (τ.(P))  τ.(P) τ  P'"
      by(auto simp add: pi.inject intro: transitions.Tau)
    ultimately show ?case by blast
  next
    case(Input a x P)
    show ?case by auto
  next
    case(Match a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Mismatch a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Sum P Q) 
    have "hnf (P  Q)" by fact
    hence Phnf: "hnf P" and Qhnf: "hnf Q" by simp+
    
    have IHP: "P τ  P' = (τ.(P')  summands P)"
    proof -
      have "hnf P  P τ  P' = (τ.(P')  summands P)" by fact
      with Phnf show ?thesis by simp
    qed
    
    have IHQ: "Q τ  P' = (τ.(P')  summands Q)"
    proof -
      have "hnf Q  Q τ  P' = (τ.(P')  summands Q)" by fact
      with Qhnf show ?thesis by simp
    qed

    from IHP IHQ have "P  Q τ  P'  τ.(P')  summands (P  Q)"
      by(erule_tac sumCases, auto)
    moreover from IHP IHQ have "τ.(P')  summands (P  Q)  P  Q τ  P'"
      by(auto dest: Sum1 Sum2)
    ultimately show ?case by blast
  next
    case(Par P Q)
    have "hnf (P  Q)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Res x P)
    thus ?case by(auto elim: resCasesF)
  next
    case(Bang P)
    have "hnf (!P)" by fact
    hence False by simp
    thus ?case by simp
  qed
next
  from assms show "P a<x>  P' = (a<x>.P'  summands P)"
  proof(induct P rule: pi.induct)
    case PiNil
    show ?case by auto
  next
    case(Output c b P)
    show ?case by auto
  next
    case(Tau P)
    show ?case by auto
  next
    case(Input b y P)
    have "b<y>.P a<x>  P'  a<x>.P'  summands (b<y>.P)"
      by(auto elim: inputCases' simp add: pi.inject residual.inject)
    moreover have "a<x>.P'  summands (b<y>.P)  b<y>.P a<x>  P'"
      apply(auto simp add: pi.inject name_abs_eq intro: Late_Semantics.Input)
      apply(subgoal_tac "b<x>  [(x, y)]  P = (b<y>  [(x, y)]  [(x, y)]  P)")
      apply(auto intro: Late_Semantics.Input)
      by(simp add: alphaBoundResidual name_swap)
    ultimately show ?case by blast
  next
    case(Match a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Mismatch a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Sum P Q) 
    have "hnf (P  Q)" by fact
    hence Phnf: "hnf P" and Qhnf: "hnf Q" by simp+
    
    have IHP: "P a<x>  P' = (a<x>.P'  summands P)"
    proof -
      have "hnf P  P a<x>  P' = (a<x>.P'  summands P)" by fact
      with Phnf show ?thesis by simp
    qed
    
    have IHQ: "Q a<x>  P' = (a<x>.P'  summands Q)"
    proof -
      have "hnf Q  Q a<x>  P' = (a<x>.P'  summands Q)" by fact
      with Qhnf show ?thesis by simp
    qed

    from IHP IHQ have "P  Q a<x>  P'  a<x>.P'  summands (P  Q)"
      by(erule_tac sumCases, auto)
    moreover from IHP IHQ have "a<x>.P'  summands (P  Q)  P  Q a<x>  P'"
      by(auto dest: Sum1 Sum2)
    ultimately show ?case by blast
  next
    case(Par P Q)
    have "hnf (P  Q)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Res y P)
    have "hnf(y>P)" by fact
    thus ?case by(auto simp add: if_split)
  next
    case(Bang P)
    have "hnf (!P)" by fact
    hence False by simp
    thus ?case by simp
  qed
next
  from assms show "P a[b]  P' = (a{b}.P'  summands P)"
  proof(induct P rule: pi.induct)
    case PiNil
    show ?case by auto
  next
    case(Output c d P)
    have "c{d}.P a[b]  P'  a{b}.P'  summands (c{d}.P)"
      by(auto elim: outputCases simp add: residual.inject pi.inject)
    moreover have "a{b}.P'  summands (c{d}.P)  c{d}.P a[b]  P'"
      by(auto simp add: pi.inject intro: transitions.Output)
    ultimately show ?case by blast
  next
    case(Tau P)
    show ?case by auto
  next
    case(Input c x P)
    show ?case by auto
  next
    case(Match a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Mismatch a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Sum P Q) 
    have "hnf (P  Q)" by fact
    hence Phnf: "hnf P" and Qhnf: "hnf Q" by simp+
    
    have IHP: "P a[b]  P' = (a{b}.P'  summands P)"
    proof -
      have "hnf P  P a[b]  P' = (a{b}.P'  summands P)" by fact
      with Phnf show ?thesis by simp
    qed
    
    have IHQ: "Q a[b]  P' = (a{b}.P'  summands Q)"
    proof -
      have "hnf Q  Q a[b]  P' = (a{b}.P'  summands Q)" by fact
      with Qhnf show ?thesis by simp
    qed

    from IHP IHQ have "P  Q a[b]  P'  a{b}.P'  summands (P  Q)"
      by(erule_tac sumCases, auto)
    moreover from IHP IHQ have "a{b}.P'  summands (P  Q)  P  Q a[b]  P'"
      by(auto dest: Sum1 Sum2)
    ultimately show ?case by blast
  next
    case(Par P Q)
    have "hnf (P  Q)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Res x P)
    have "hnf (x>P)" by fact
    thus ?case by(force elim: resCasesF outputCases simp add: if_split residual.inject)
  next
    case(Bang P)
    have "hnf (!P)" by fact
    hence False by simp
    thus ?case by simp
  qed
next
  assume "ax"
  with assms show "P ax>  P' = (x>a{x}.P'  summands P)"
  proof(nominal_induct P avoiding: x P' rule: pi.strong_induct)
    case PiNil
    show ?case by auto
  next
    case(Output a b P)
    show ?case by auto 
  next
    case(Tau P)
    show ?case by auto
  next
    case(Input a x P)
    show ?case by auto
  next
    case(Match a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Mismatch a b P)
    have "hnf ([ab]P)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Sum P Q) 
    have "hnf (P  Q)" by fact
    hence Phnf: "hnf P" and Qhnf: "hnf Q" by simp+
    have aineqx: "a  x" by fact

    have IHP: "P ax>  P' = (x>a{x}.P'  summands P)"
    proof -
      have "x P'. hnf P; a  x  P ax>  P' = (x>a{x}.P'  summands P)" by fact
      with Phnf aineqx show ?thesis by simp
    qed
    
    have IHQ: "Q ax>  P' = (x>a{x}.P'  summands Q)"
    proof -
      have "x Q'. hnf Q; a  x  Q ax>  P' = (x>a{x}.P'  summands Q)" by fact
      with Qhnf aineqx show ?thesis by simp
    qed

    from IHP IHQ have "P  Q ax>  P'  x>a{x}.P'  summands (P  Q)"
      by(erule_tac sumCases, auto)
    moreover from IHP IHQ have "x>a{x}.P'  summands (P  Q)  P  Q ax>  P'"
      by(auto dest: Sum1 Sum2)
    ultimately show ?case by blast
  next
    case(Par P Q)
    have "hnf (P  Q)" by fact
    hence False by simp
    thus ?case by simp
  next
    case(Res y P)
    have Phnf: "hnf (y>P)" by fact
    then obtain b P'' where bineqy: "b  y" and PeqP'': "P = b{y}.P''"
      by auto
    have "y  x" by fact hence xineqy:  "x  y" by simp
    have yFreshP': "y  P'" by fact
    have aineqx: "ax" by fact
    have "y>P ax>  P'  (x>a{x}.P'  summands (y>P))"
    proof -
      assume Trans: "y>P ax>  P'"
      hence  aeqb: "a = b" using xineqy bineqy PeqP''
        by(induct rule: resCasesB', auto elim: outputCases simp add: residual.inject alpha' abs_fresh pi.inject)

      have Goal: "x P'. y>b{y}.P'' bx>  P'; x  y; x  b; x  P'' 
                           x>b{x}.P'  summands(y>b{y}.P'')"
      proof -
        fix x P'
        assume xFreshP'': "(x::name)  P''" and xineqb: "x  b"
        assume "y>b{y}.P'' bx>  P'" and xineqy: "x  y"
        moreover from x  b x  P'' x  y have "x  b{y}.P''" by simp
        ultimately show "x>b{x}.P'  summands (y>b{y}.P'')"
        proof(induct rule: resCasesB)
          case(cOpen a P''')
          have "BoundOutputS b = BoundOutputS a" by fact hence beqa: "b = a" by simp
          have Trans: "b{y}.P'' a[y]  P'''" by fact
          with PeqP'' have P''eqP''': "P'' = P'''"
            by(force elim: outputCases simp add: residual.inject)
          with bineqy xineqy xFreshP'' have "y  b{x}.([(x, y)]  P''')"
            by(simp add: name_fresh_abs name_calc name_fresh_left)
          with bineqy Phnf PeqP'' P''eqP''' xineqb show ?case 
            by(simp only: alphaRes, simp add: name_calc)
        next
          case(cRes P''')
          have "b{y}.P'' bx>  P'''" by fact
          hence False by auto
          thus ?case by simp
        qed     
      qed
      obtain z where zineqx: "z  x" and zineqy: "z  y" and zFreshP'': "z  P''" 
                 and zineqb: "z  b" and zFreshP': "z  P'"
        by(force intro: name_exists_fresh[of "(x, y, b, P'', P')"] simp add: fresh_prod)

      from zFreshP' aeqb PeqP'' Trans have Trans': "y>b{y}.P'' bz>  [(z, x)]  P'"
        by(simp add: alphaBoundResidual name_swap)
      hence "z>b{z}.([(z, x)]  P')  summands (y>b{y}.P'')" using zineqy zineqb zFreshP''
        by(rule Goal)
      moreover from bineqy zineqx zFreshP' aineqx aeqb have "x  b{z}.([(z, x)]  P')"
        by(simp add: name_fresh_left name_calc)
      ultimately have "x>b{x}.P'  summands (y>b{y}.P'')" using zineqb
        by(simp add: alphaRes name_calc)
      with aeqb PeqP'' show ?thesis by blast
    qed
    moreover have "x>a{x}.P'  summands(y>P)  y>P ax>  P'"
    proof -
      assume "x>a{x}.P'  summands(y>P)"
      with PeqP'' have Summ: "x>a{x}.P'  summands(y>b{y}.P'')" by simp
      moreover with bineqy xineqy have aeqb: "a = b" 
        by(auto simp add: if_split pi.inject name_abs_eq name_fresh_fresh)
      from bineqy xineqy yFreshP' have "y  b{x}.P'" by(simp add: name_calc)
      with Summ aeqb bineqy aineqx have "y>b{y}.([(x, y)]  P')  summands(y>b{y}.P'')"
        by(simp only: alphaRes, simp add: name_calc)
      with aeqb PeqP'' have "y>P ay>  [(x, y)]  P'"
        by(auto intro: Open Output simp add: if_split pi.inject name_abs_eq)
      moreover from yFreshP' have "x  [(x, y)]  P'" by(simp add: name_fresh_left name_calc)
      ultimately show ?thesis by(simp add: alphaBoundResidual name_swap)
    qed
    ultimately show ?case by blast
  next
    case(Bang P)
    have "hnf (!P)" by fact
    hence False by simp
    thus ?case by simp
  qed
qed

definition "expandSet" :: "pi  pi  pi set" where
          "expandSet P Q  {τ.(P'  Q) | P'. τ.(P')  summands P}  
                           {τ.(P  Q') | Q'. τ.(Q')  summands Q}  
                           {a{b}.(P'  Q) | a b P'. a{b}.P'  summands P} 
                           {a{b}.(P  Q') | a b Q'. a{b}.Q'  summands Q} 
                           {a<x>.(P'  Q) | a x P'. a<x>.P'  summands P  x  Q} 
                           {a<x>.(P  Q') | a x Q'. a<x>.Q'  summands Q  x  P} 
                           {x>a{x}.(P'  Q) | a x P'. x>a{x}.P'  summands P  x  Q}  
                           {x>a{x}.(P  Q') | a x Q'. x>a{x}.Q'  summands Q  x  P}  
                           {τ.(P'[x::=b]  Q') | x P' b Q'. a. a<x>.P'  summands P  a{b}.Q'  summands Q}  
                           {τ.(P'  (Q'[x::=b])) | b P' x Q'. a. a{b}.P'  summands P  a<x>.Q'  summands Q}  
                           {τ.(y>(P'[x::=y]  Q')) | x P' y Q'. a. a<x>.P'  summands P  y>a{y}.Q'  summands Q  y  P} 
                           {τ.(y>(P'  (Q'[x::=y]))) | y P' x Q'. a. y>a{y}.P'  summands P  a<x>.Q'  summands Q  y  Q}"

lemma finiteExpand:
  fixes P :: pi
  and   Q :: pi

  shows "finite(expandSet P Q)"
proof -
  have "finite {τ.(P'  Q) | P'. τ.(P')  summands P}"
    by(induct P rule: pi.induct, auto simp add: pi.inject Collect_ex_eq conj_disj_distribL
                                                           Collect_disj_eq UN_Un_distrib)
  moreover have "finite {τ.(P  Q') | Q'. τ.(Q')  summands Q}"
    by(induct Q rule: pi.induct, auto simp add: pi.inject Collect_ex_eq conj_disj_distribL
                                                           Collect_disj_eq UN_Un_distrib)
  moreover have "finite {a{b}.(P'  Q) | a b P'. a{b}.P'  summands P}"
    by(induct P rule: pi.induct, auto simp add: pi.inject Collect_ex_eq conj_disj_distribL
                                                           Collect_disj_eq UN_Un_distrib)
  moreover have "finite {a{b}.(P  Q') | a b Q'. a{b}.Q'  summands Q}"
    by(induct Q rule: pi.induct, auto simp add: pi.inject Collect_ex_eq conj_disj_distribL
                                                           Collect_disj_eq UN_Un_distrib)
  moreover have "finite {a<x>.(P'  Q) | a x P'. a<x>.P'  summands P  x  Q}"
  proof -
    have Aux: "a x P Q. (x::name)  Q  {a'<x'>.(P'  Q) |a' x' P'. a'<x'>.P' = a<x>.P  x'  Q} = {a<x>.(P  Q)}"
      by(auto simp add: pi.inject name_abs_eq name_fresh_fresh)
    thus ?thesis
      by(nominal_induct P avoiding: Q rule: pi.strong_induct,
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib)
  qed
  moreover have "finite {a<x>.(P  Q') | a x Q'. a<x>.Q'  summands Q  x  P}"
  proof -
    have Aux: "a x P Q. (x::name)  P  {a'<x'>.(P  Q') |a' x' Q'. a'<x'>.Q' = a<x>.Q  x'  P} = {a<x>.(P  Q)}"
      by(auto simp add: pi.inject name_abs_eq name_fresh_fresh)
    thus ?thesis
      by(nominal_induct Q avoiding: P rule: pi.strong_induct,
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib)
  qed
  moreover have "finite {x>a{x}.(P'  Q) | a x P'. x>a{x}.P'  summands P  x  Q}"
  proof -
    have Aux: "a x P Q. x  Q; a  x  {x'>a'{x'}.(P'  Q) |a' x' P'. x'>a'{x'}.P' = x>a{x}.P  x'  Q} = 
                                             {x>a{x}.(P  Q)}"
      by(auto simp add: pi.inject name_abs_eq name_fresh_fresh)
    thus ?thesis
      by(nominal_induct P avoiding: Q rule: pi.strong_induct, 
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib)
  qed
  moreover have "finite {x>a{x}.(P  Q') | a x Q'. x>a{x}.Q'  summands Q  x  P}"
  proof -
    have Aux: "a x P Q. x  P; a  x  {x'>a'{x'}.(P  Q') |a' x' Q'. x'>a'{x'}.Q' = x>a{x}.Q  x'  P} = 
                                             {x>a{x}.(P  Q)}"
      by(auto simp add: pi.inject name_abs_eq name_fresh_fresh)
    thus ?thesis
      by(nominal_induct Q avoiding: P rule: pi.strong_induct, 
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib)
  qed
  moreover have "finite {τ.(P'[x::=b]  Q') | x P' b Q'. a. a<x>.P'  summands P  a{b}.Q'  summands Q}"
  proof -
    have Aux: "a x P b Q. {τ.(P'[x'::=b']  Q') | a' x' P' b' Q'. a'<x'>.P' = a<x>.P  a'{b'}.Q' = a{b}.Q} = {τ.(P[x::=b]  Q)}"
      by(auto simp add: name_abs_eq pi.inject renaming)
    have "a x P Q b::'a::{}. finite {τ.(P'[x'::=b]  Q') | a' x' P' b Q'. a'<x'>.P' = a<x>.P  a'{b}.Q'  summands Q}"
      apply(induct rule: pi.induct, simp_all)
      apply(case_tac "a=name1")
      apply(simp add: Aux)
      apply(simp add: pi.inject)
      by(simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                   Collect_disj_eq UN_Un_distrib)
    hence "finite {τ.(P'[x::=b]  Q') | a x P' b Q'. a<x>.P'  summands P  a{b}.Q'  summands Q}"
      by(nominal_induct P avoiding: Q rule: pi.strong_induct,
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib name_abs_eq)
    thus ?thesis 
      apply(rule_tac finite_subset)
      defer
      by blast+
  qed
  moreover have "finite {τ.(P'  (Q'[x::=b])) | b P' x Q'. a. a{b}.P'  summands P  a<x>.Q'  summands Q}"
  proof -
      have Aux: "a x P b Q. {τ.(P'  (Q'[x'::=b'])) | a' b' P' x' Q'. a'{b'}.P' = a{b}.P  a'<x'>.Q' = a<x>.Q} = {τ.(P  (Q[x::=b]))}"
        by(auto simp add: name_abs_eq pi.inject renaming)
      have "a b P Q x::'a::{}. finite {τ.(P'  (Q'[x::=b'])) | a' b' P' x Q'. a'{b'}.P' = a{b}.P  a'<x>.Q'  summands Q}"
      apply(induct rule: pi.induct, simp_all)
      apply(case_tac "a=name1")
      apply(simp add: Aux)
      apply(simp add: pi.inject)
      by(simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                     Collect_disj_eq UN_Un_distrib)
    hence "finite {τ.(P'  (Q'[x::=b])) | a b P' x Q'. a{b}.P'  summands P  a<x>.Q'  summands Q}"
      by(nominal_induct P avoiding: Q rule: pi.strong_induct,
         auto simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib name_abs_eq)
    thus ?thesis
      apply(rule_tac finite_subset) defer by blast+
  qed
  moreover have "finite {τ.(y>(P'[x::=y]  Q')) | x P' y Q'. a. a<x>.P'  summands P  y>a{y}.Q'  summands Q  y  P}"
  proof -
    have Aux: "a x P y Q. y  P  y  a  {τ.(y'>(P'[x'::=y']  Q')) | a' x' P' y' Q'. a'<x'>.P' = a<x>.P  y'>a'{y'}.Q' = y>a{y}.Q  y'  a<x>.P} = {τ.(y>(P[x::=y]  Q))}"
      apply(auto simp add: pi.inject name_abs_eq name_fresh_abs name_calc fresh_fact2 fresh_fact1 eqvts forget)
      apply(subst name_swap, simp add: injPermSubst fresh_fact1 fresh_fact2)+
      by(simp add: name_swap injPermSubst)+

    have BC: "a x P Q. finite {τ.(y>(P'[x'::=y]  Q')) | a' x' P' y Q'. a'<x'>.P' = a<x>.P  y>a'{y}.Q'  summands Q  y  a<x>.P}"
    proof -
      fix a x P Q
      show "finite {τ.(y>(P'[x'::=y]  Q')) | a' x' P' y Q'. a'<x'>.P' = a<x>.P  y>a'{y}.Q'  summands Q  y  a<x>.P}"
        apply(nominal_induct Q avoiding: a P rule: pi.strong_induct, simp_all)
        apply(simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR
                        Collect_disj_eq UN_Un_distrib)
        apply(clarsimp)
        apply(case_tac "a=aa")
        apply(insert Aux, auto)
        by(simp add: pi.inject name_abs_eq name_calc)
    qed

    have IH: "P P' Q. {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. (a<x>.P''  summands P  a<x>.P''  summands P')  y>a{y}.Q'  summands Q  y  P  y  P'} = {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P  y>a{y}.Q'  summands Q  y  P  y  P'}  {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P'  y>a{y}.Q'  summands Q  y  P  y  P'}"
      by blast
    have IH': "P Q P'. {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P  y>a{y}.Q'  summands Q  y  P  y  P'}  {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P  y>a{y}.Q'  summands Q  y  P}"
      by blast
    have IH'': "P Q P'. {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P'  y>a{y}.Q'  summands Q  y  P  y  P'}  {τ.(y>(P''[x::=y]  Q')) | a x P'' y Q'. a<x>.P''  summands P'  y>a{y}.Q'  summands Q  y  P'}"
      by blast
    have "finite {τ.(y>(P'[x::=y]  Q')) | a x P' y Q'. a<x>.P'  summands P  y>a{y}.Q'  summands Q  y  P}"
      apply(nominal_induct P avoiding: Q rule: pi.strong_induct, simp_all)
      apply(insert BC, force)
      apply(insert IH, auto)
      apply(blast intro: finite_subset[OF IH'])
      by(blast intro: finite_subset[OF IH''])
    thus ?thesis
      apply(rule_tac finite_subset) defer by(blast)+
  qed
  moreover have "finite {τ.(y>(P'  (Q'[x::=y]))) | y P' x Q'. a. y>a{y}.P'  summands P  a<x>.Q'  summands Q  y  Q}"
  proof -
    have Aux: "a y P x Q. y  Q; y  a  {τ.(y'>(P'  (Q'[x'::=y']))) | a' y' P' x' Q'. y'>a'{y'}.P' = y>a{y}.P  a'<x'>.Q' = a<x>.Q  y'  a<x>.Q} = {τ.(y>(P  (Q[x::=y])))}"
      apply(auto simp add: pi.inject name_abs_eq name_fresh_abs name_calc fresh_fact2 fresh_fact1 forget eqvts fresh_left renaming[symmetric])
      apply(subst name_swap, simp add: injPermSubst fresh_fact1 fresh_fact2)+
      by(simp add: name_swap injPermSubst)+

    have IH: "P y a Q Q'. {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  (a'<x>.Q''  summands Q  a'<x>.Q''  summands Q')  y'  Q  y'  Q'} = {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q  y'  Q  y'  Q'}  {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q'  y'  Q  y'  Q'}"
      by blast
    have IH': "a y P Q Q'. {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q  y'  Q  y'  Q'}  {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q  y'  Q}"
      by blast
    have IH'': "a y P Q Q'. {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q'  y'  Q  y'  Q'}  {τ.(y'>(P'  (Q''[x::=y']))) | a' y' P' x Q''. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q''  summands Q'  y'  Q'}"
      by blast

    have BC: "a y P Q. y  Q; y  a  finite {τ.(y'>(P'  (Q'[x::=y']))) | a' y' P' x Q'. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q'  summands Q  y'  Q}"
    proof -
      fix a y P Q
      assume "(y::name)  (Q::pi)" and "y  a"
      thus "finite {τ.(y'>(P'  (Q'[x::=y']))) | a' y' P' x Q'. y'>a'{y'}.P' = y>a{y}.P  a'<x>.Q'  summands Q  y'  Q}"
        apply(nominal_induct Q avoiding: y rule: pi.strong_induct, simp_all)
        apply(case_tac "a=name1")
        apply auto
        apply(subgoal_tac "ya  (pi::pi)")
        apply(insert Aux)
        apply auto
        apply(simp add: name_fresh_abs)
        apply(simp add: pi.inject name_abs_eq name_calc)
        apply(insert IH)
        apply auto
        apply(blast intro: finite_subset[OF IH'])
        by(blast intro: finite_subset[OF IH''])
    qed
    have "finite {τ.(y>(P'  (Q'[x::=y]))) | a y P' x Q'. y>a{y}.P'  summands P  a<x>.Q'  summands Q  y  Q}"

      apply(nominal_induct P avoiding: Q rule: pi.strong_induct, simp_all)
      apply(simp add: Collect_ex_eq conj_disj_distribL conj_disj_distribR name_fresh_abs
                      Collect_disj_eq UN_Un_distrib)
      by(auto intro: BC)
    thus ?thesis
      apply(rule_tac finite_subset) defer by blast+
  qed

  ultimately show ?thesis
    by(simp add: expandSet_def)
qed

lemma expandHnf:
  fixes P :: pi
  and   Q :: pi

  shows "R  (expandSet P Q). hnf R"
by(force simp add: expandSet_def)

inductive_set sumComposeSet :: "(pi × pi set) set"
where
  empty:  "(𝟬, {})  sumComposeSet"
| insert: "Q  S; (P, S - {Q})  sumComposeSet  (P  Q, S)  sumComposeSet"

lemma expandAction:
  fixes P :: pi
  and   Q :: pi
  and   S :: "pi set"

  assumes "(P, S)  sumComposeSet"
  and     "Q  S"
  and     "Q  Rs"

  shows "P  Rs"
using assms
proof(induct arbitrary: Q rule: sumComposeSet.induct)
  case empty
  have "Q  {}" by fact
  hence False by simp
  thus ?case by simp
next
  case(insert Q' S P Q)
  have QTrans: "Q  Rs" by fact
  show ?case
  proof(case_tac "Q = Q'")
    assume "Q = Q'"
    with QTrans show "P  Q'  Rs" by(blast intro: Sum2)
  next
    assume QineqQ': "Q  Q'"
    have IH: "Q. Q  S - {Q'}; Q  Rs  P  Rs" by fact
    have QinS: "Q  S" by fact
    with QineqQ' have "Q  S - {Q'}" by simp
    hence "P  Rs" using QTrans by(rule IH)
    thus ?case by(rule Sum1)
  qed
qed

lemma expandAction':
  fixes P :: pi
  and   Q :: pi
  and   R :: pi

  assumes "(R, S)  sumComposeSet"
  and     "R  Rs"

  shows "P  S. P  Rs"
using assms
proof(induct rule: sumComposeSet.induct)
  case empty
  have "𝟬  Rs" by fact
  hence False by blast
  thus ?case by simp
next
  case(insert Q S P)
  have QinS: "Q  S" by fact
  have "P  Q  Rs" by fact
  thus ?case
  proof(induct rule: sumCases)
    case cSum1
    have "P  Rs" by fact
    moreover have "P  Rs  P  (S - {Q}). P  Rs" by fact
    ultimately obtain P where PinS: "P  (S - {Q})" and PTrans: "P  Rs" by blast
    show ?case
    proof(case_tac "P = Q")
      assume "P = Q"
      with PTrans QinS show ?case by blast
    next
      assume PineqQ: "P  Q"
      from PinS have "P  S" by simp
      with PTrans show ?thesis by blast
    qed
  next
    case cSum2
    have "Q  Rs" by fact
    with QinS show ?case by blast
  qed
qed

lemma expandTrans:
  fixes P :: pi
  and   Q :: pi
  and   R :: pi
  and   a :: name
  and   b :: name
  and   x :: name

  assumes Exp: "(R, expandSet P Q)  sumComposeSet"
  and     Phnf: "hnf P"
  and     Qhnf: "hnf Q"

  shows "(P  Q τ  P') = (R τ  P')"
  and   "(P  Q a[b]  P') = (R a[b]  P')"
  and   "(P  Q a<x>  P') = (R a<x>  P')"
  and   "(P  Q ax>  P') = (R ax>  P')"
proof -
  show "P  Q  τ  P' = R  τ  P'"
  proof(rule iffI)
    assume "P  Q τ  P'"
    thus "R τ  P'"
    proof(induct rule: parCasesF[of _ _ _ _ _ "(P, Q)"])
      case(cPar1 P')
      have "P τ  P'" by fact
      with Phnf have "τ.(P')  summands P" by(simp add: summandTransition)
      hence "τ.(P'  Q)  expandSet P Q" by(auto simp add: expandSet_def)
      moreover have "τ.(P'  Q) τ  (P'  Q)" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cPar2 Q')
      have "Q τ  Q'" by fact
      with Qhnf have "τ.(Q')  summands Q" by(simp add: summandTransition)
      hence "τ.(P  Q')  expandSet P Q" by(auto simp add: expandSet_def)
      moreover have "τ.(P  Q') τ  (P  Q')" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cComm1 P' Q' a b x)
      have "P a<x>  P'" and "Q a[b]  Q'" by fact+
      with Phnf Qhnf have "a<x>.P'  summands P" and "a{b}.Q'  summands Q" by(simp add: summandTransition)+
      hence "τ.(P'[x::=b]  Q')  expandSet P Q" by(simp add: expandSet_def, blast)
      moreover have "τ.(P'[x::=b]  Q') τ  (P'[x::=b]  Q')" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cComm2 P' Q' a b x)
      have "P a[b]  P'" and "Q a<x>  Q'" by fact+
      with Phnf Qhnf have "a{b}.P'  summands P" and "a<x>.Q'  summands Q" by(simp add: summandTransition)+
      hence "τ.(P'  (Q'[x::=b]))  expandSet P Q" by(simp add: expandSet_def, blast)
      moreover have "τ.(P'  (Q'[x::=b])) τ  (P'  (Q'[x::=b]))" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cClose1 P' Q' a x y)
      have "y  (P, Q)" by fact
      hence yFreshP: "y  P" by(simp add: fresh_prod)
      have PTrans: "P a<x>  P'" by fact
      with Phnf have PSumm: "a<x>.P'  summands P" by(simp add: summandTransition)
      have "Q ay>  Q'" by fact
      moreover from PTrans yFreshP have "y  a" by(force dest: freshBoundDerivative)
      ultimately have "y>a{y}.Q'  summands Q" using Qhnf by(simp add: summandTransition)
      with PSumm yFreshP have "τ.(y>(P'[x::=y]  Q'))  expandSet P Q"
        by(auto simp add: expandSet_def)
      moreover have "τ.(y>(P'[x::=y]  Q')) τ  y>(P'[x::=y]  Q')" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cClose2 P' Q' a x y)
      have "y  (P, Q)" by fact
      hence yFreshQ: "y  Q" by(simp add: fresh_prod)
      have QTrans: "Q a<x>  Q'" by fact
      with Qhnf have QSumm: "a<x>.Q'  summands Q" by(simp add: summandTransition)
      have "P ay>  P'" by fact
      moreover from QTrans yFreshQ have "y  a" by(force dest: freshBoundDerivative)
      ultimately have "y>a{y}.P'  summands P" using Phnf by(simp add: summandTransition)
      with QSumm yFreshQ have "τ.(y>(P'  (Q'[x::=y])))  expandSet P Q"
        by(simp add: expandSet_def, blast)
      moreover have "τ.(y>(P'  (Q'[x::=y]))) τ  y>(P'  (Q'[x::=y]))" by(rule Tau)
      ultimately show ?case using Exp by(blast intro: expandAction)
    qed
  next
    assume "R τ  P'"
    with Exp obtain R where "R  expandSet P Q" and "R τ  P'" by(blast dest: expandAction')
    thus "P  Q τ  P'"
    proof(auto simp add: expandSet_def)
      fix P''
      assume "τ.(P'')  summands P"
      with Phnf have "P τ  P''" by(simp add: summandTransition)
      hence PQTrans: "P  Q τ  P''  Q" by(rule Par1F)
      assume "τ.(P''  Q) τ  P'"
      hence "P' = P''  Q" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    next
      fix Q'
      assume "τ.(Q')  summands Q"
      with Qhnf have "Q τ  Q'" by(simp add: summandTransition)
      hence PQTrans: "P  Q τ  P  Q'" by(rule Par2F)
      assume "τ.(P  Q') τ  P'"
      hence "P' = P  Q'" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    next
      fix a x P'' b Q'
      assume "a<x>.P''  summands P" and "a{b}.Q'  summands Q"
      with Phnf Qhnf have "P a<x>  P''" and "Q a[b]  Q'" by(simp add: summandTransition)+
      hence PQTrans: "P  Q τ  P''[x::=b]  Q'" by(rule Comm1)
      assume "τ.(P''[x::=b]  Q') τ  P'"
      hence "P' = P''[x::=b]  Q'" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    next
      fix a b P'' x Q'
      assume "a{b}.P''  summands P" and "a<x>.Q'  summands Q"
      with Phnf Qhnf have "P a[b]  P''" and "Q a<x>  Q'" by(simp add: summandTransition)+
      hence PQTrans: "P  Q τ  P''  (Q'[x::=b])" by(rule Comm2)
      assume "τ.(P''  (Q'[x::=b])) τ  P'"
      hence "P' = P''  (Q'[x::=b])" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    next
      fix a x P'' y Q'
      assume yFreshP: "(y::name)  P"
      assume "a<x>.P''  summands P" 
      with Phnf have PTrans: "P a<x>  P''" by(simp add: summandTransition)
      assume "y>a{y}.Q'  summands Q"
      moreover from yFreshP PTrans have "y  a" by(force dest: freshBoundDerivative)
      ultimately have "Q ay>  Q'" using Qhnf by(simp add: summandTransition)
      with PTrans have PQTrans: "P  Q τ  y>(P''[x::=y]  Q')" using yFreshP by(rule Close1)
      assume "τ.(y>(P''[x::=y]  Q')) τ  P'"
      hence "P' = y>(P''[x::=y]  Q')" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    next
      fix a y P'' x Q'
      assume yFreshQ: "(y::name)  Q"
      assume "a<x>.Q'  summands Q" 
      with Qhnf have QTrans: "Q a<x>  Q'" by(simp add: summandTransition)
      assume "y>a{y}.P''  summands P"
      moreover from yFreshQ QTrans have "y  a" by(force dest: freshBoundDerivative)
      ultimately have "P ay>  P''" using Phnf by(simp add: summandTransition)
      hence PQTrans: "P  Q τ  y>(P''  Q'[x::=y])" using QTrans yFreshQ by(rule Close2)
      assume "τ.(y>(P''  Q'[x::=y])) τ  P'"
      hence "P' = y>(P''  Q'[x::=y])" by(erule_tac tauCases, auto simp add: pi.inject residual.inject)
      with PQTrans show ?thesis by simp
    qed
  qed
next
  show "P  Q  a[b]  P' = R  a[b]  P'"
  proof(rule iffI)
    assume "P  Q a[b]  P'"
    thus "R a[b]  P'"
    proof(induct rule: parCasesF[where C="()"])
      case(cPar1 P')
      have "P a[b]  P'" by fact
      with Phnf have "a{b}.P'  summands P" by(simp add: summandTransition)
      hence "a{b}.(P'  Q)  expandSet P Q" by(auto simp add: expandSet_def)
      moreover have "a{b}.(P'  Q) a[b]  (P'  Q)" by(rule Output)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next
      case(cPar2 Q')
      have "Q a[b]  Q'" by fact
      with Qhnf have "a{b}.Q'  summands Q" by(simp add: summandTransition)
      hence "a{b}.(P  Q')  expandSet P Q" by(simp add: expandSet_def, blast)
      moreover have "a{b}.(P  Q') a[b]  (P  Q')" by(rule Output)
      ultimately show ?case using Exp by(blast intro: expandAction)
    next 
      case cComm1
      thus ?case by auto
    next 
      case cComm2
      thus ?case by auto
    next 
      case cClose1
      thus ?case by auto
    next 
      case cClose2
      thus ?case by auto
    qed
  next
    assume "R a[b]  P'"
    with Exp obtain R where "R  expandSet P Q" and "R a[b]  P'" by(blast dest: expandAction')
    thus "P  Q a[b]  P'"
    proof(auto simp add: expandSet_def)
      fix a' b' P''
      assume "a'{b'}.P''  summands P"
      with Phnf have "P a'[b']  P''" by(simp add: summandTransition)
      hence PQTrans: "P  Q a'[b']  P''  Q" by(rule Par1F)
      assume "a'{b'}.(P''  Q) a[b]  P'"
      hence "P' = P''  Q" and "a = a'" and "b = b'"
        by(erule_tac outputCases, auto simp add: pi.inject residual.inject)+
      with PQTrans show ?thesis by simp
    next
      fix a' b' Q'
      assume "a'{b'}.Q'  summands Q"
      with Qhnf have "Q a'[b']  Q'" by(simp add: summandTransition)
      hence PQTrans: "P  Q a'[b']  P  Q'" by(rule Par2F)
      assume "a'{b'}.(P  Q') a[b]  P'"
      hence "P' = P  Q'" and "a = a'" and "b = b'"
        by(erule_tac outputCases, auto simp add: pi.inject residual.inject)+
      with PQTrans show ?thesis by simp
    qed
  qed
next
  show "P  Q  a<x>  P' = R  a<x>  P'"
  proof(rule iffI)
    {
      fix x P'
      assume "P  Q a<x>  P'" and "x  P" and "x  Q"
      hence "R a<x>  P'"
      proof(induct rule: parCasesB)
        case(cPar1 P')
        have "P a<x>  P'" by fact
        with Phnf have "a<x>.P'  summands P" by(simp add: summandTransition)
        moreover have "x  Q" by fact
        ultimately have "a<x>.(P'  Q)  expandSet P Q" by(auto simp add: expandSet_def)
        moreover have "a<x>.(P'  Q) a<x>  (P'  Q)" by(rule Input)
        ultimately show ?case using Exp by(blast intro: expandAction)
      next
        case(cPar2 Q')
        have "Q a<x>  Q'" by fact
        with Qhnf have "a<x>.Q'  summands Q" by(simp add: summandTransition)
        moreover have "x  P" by fact
        ultimately have "a<x>.(P  Q')  expandSet P Q" by(simp add: expandSet_def, blast)
        moreover have "a<x>.(P  Q') a<x>  (P  Q')" by(rule Input)
        ultimately show ?case using Exp by(blast intro: expandAction)
      qed
    }
    moreover obtain y::name where "y  P" and "y  Q" and "y  P'"
      by(generate_fresh "name") auto
    assume "P  Q a<x>  P'"
    with y  P' have "P  Q a<y>  ([(x, y)]  P')"
      by(simp add: alphaBoundResidual)
    ultimately have "R a<y>  ([(x, y)]  P')" using y  P y  Q
      by auto
    thus "R a<x>  P'" using y  P' by(simp add: alphaBoundResidual)
  next
    assume "R a<x>  P'"
    with Exp obtain R where "R  expandSet P Q" and "R a<x>  P'" by(blast dest: expandAction')
    thus "P  Q a<x>  P'"
    proof(auto simp add: expandSet_def)
      fix a' y P''
      assume "a'<y>.P''  summands P"
      with Phnf have "P a'<y>  P''" by(simp add: summandTransition)
      moreover assume "y  Q"
      ultimately have PQTrans: "P  Q a'<y>  P''  Q" by(rule Par1B)
      assume "a'<y>.(P''  Q) a<x>  P'"
      hence "a<x>  P' = a'<y>  P''  Q" and "a = a'"
        by(erule_tac inputCases', auto simp add: pi.inject residual.inject)+
      with PQTrans show ?thesis by simp
    next
      fix a' y Q'
      assume "a'<y>.Q'  summands Q"
      with Qhnf have "Q (a'::name)<y>  Q'" by(simp add: summandTransition)
      moreover assume "y  P"
      ultimately have PQTrans: "P  Q a'<y>  P  Q'" by(rule Par2B)
      assume "a'<y>.(P  Q') a<x>  P'"
      hence "a<x>  P' = a'<y>  P  Q'" and "a = a'"
        by(erule_tac inputCases', auto simp add: pi.inject residual.inject)+
      with PQTrans show ?thesis by simp
    qed
  qed
next
  have Goal: "P Q a x P' R. (R, expandSet P Q)  sumComposeSet; hnf P; hnf Q; a  x  P  Q ax>  P' = R ax>  P'"
  proof -
    fix P Q a x P' R
    assume aineqx: "(a::name)  x"
    assume Exp: "(R, expandSet P Q)  sumComposeSet"
    assume Phnf: "hnf P"
    assume Qhnf: "hnf Q"
    show "P  Q ax>  P' = R  ax>  P'"
    proof(rule iffI)
      {
        fix x P'
        assume "P  Q ax>  P'" and "x  P" and "x  Q" and "a  x"
        hence "R ax>  P'"
        proof(induct rule: parCasesB)
          case(cPar1 P')
          have "P ax>  P'" by fact
          with Phnf a  x have "x>a{x}.P'  summands P" by(simp add: summandTransition)
          moreover have "x  Q" by fact
          ultimately have "x>a{x}.(P'  Q)  expandSet P Q" by(auto simp add: expandSet_def)
          moreover have "x>a{x}.(P'  Q) ax>  (P'  Q)" using a  x
            by(blast intro: Open Output)
          ultimately show ?case using Exp by(blast intro: expandAction)
        next
          case(cPar2 Q')
          have "Q ax>  Q'" by fact
          with Qhnf a  x have "x>a{x}.Q'  summands Q" by(simp add: summandTransition)
          moreover have "x  P" by fact
          ultimately have "x>a{x}.(P  Q')  expandSet P Q" by(simp add: expandSet_def, blast)
          moreover have "x>a{x}.(P  Q') ax>  (P  Q')" using a  x
            by(blast intro: Open Output)
          ultimately show ?case using Exp by(blast intro: expandAction)
        qed
      }
      moreover obtain y::name where "y  P" and "y  Q" and "y  P'" and "y  a"
        by(generate_fresh "name") auto
      assume "P  Q ax>  P'"
      with y  P' have "P  Q ay>  ([(x, y)]  P')"
        by(simp add: alphaBoundResidual)
      ultimately have "R ay>  ([(x, y)]  P')" using y  P y  Q y  a
        by auto
      thus "R ax>  P'" using y  P' by(simp add: alphaBoundResidual)
    next
      {
        fix R x P'
        assume "R ax>  P'" and "R  expandSet P Q" and "x  R" and "x  P" and "x  Q"
        hence "P  Q ax>  P'" 
        proof(auto simp add: expandSet_def)
          fix a' y P''
          assume "y>a'{y}.P''  summands P"
          moreover hence "a'  y" by auto
          ultimately have "P a'y>  P''" using Phnf by(simp add: summandTransition)
          moreover assume "y  Q"
          ultimately have PQTrans: "P  Q a'y>  P''  Q" by(rule Par1B)
          assume ResTrans: "y>a'{y}.(P''  Q) ax>  P'" and "x  [y].a'{y}.(P''  Q)"
          with ResTrans a'  y x  P x  Q have "ax>  P' = a'y>  P''  Q"
            apply(case_tac "x=y")
            defer
            apply(erule_tac resCasesB)
            apply simp
            apply(simp add: abs_fresh)
            apply(auto simp add: residual.inject alpha' calc_atm fresh_left abs_fresh elim: outputCases)
            apply(ind_cases "y>a'{y}.(P''  Q)  ay>  P'")
            apply(simp add: pi.inject alpha' residual.inject abs_fresh eqvts calc_atm)
            apply(auto elim: outputCases)
            apply(simp add: pi.inject residual.inject alpha' calc_atm)
            apply auto
            apply(ind_cases "y>a'{y}.(P''  Q)  ay>  P'")
            apply(auto simp add: pi.inject alpha' residual.inject abs_fresh eqvts calc_atm)
            apply(auto elim: outputCases)
            apply(erule_tac outputCases)
            apply(auto simp add: freeRes.inject)
            apply hypsubst_thin
            apply(drule_tac pi="[(b, y)]" in pt_bij3)
            by simp
        with PQTrans show ?thesis by simp
      next
        fix a' y Q'
        assume "y>a'{y}.Q'  summands Q"
        moreover hence "a'  y" by auto
        ultimately have "Q a'y>  Q'" using Qhnf by(simp add: summandTransition)
        moreover assume "y  P"
        ultimately have PQTrans: "P  Q a'y>  P  Q'" by(rule Par2B)
        assume ResTrans: "y>a'{y}.(P  Q') ax>  P'" and "x  [y].a'{y}.(P  Q')"
        with ResTrans a'  y have "ax>  P' = a'y>  P  Q'"
          apply(case_tac "x=y")
          defer
          apply(erule_tac resCasesB)
            apply simp
            apply(simp add: abs_fresh)
            apply(auto simp add: residual.inject alpha' calc_atm fresh_left abs_fresh elim: outputCases)
            apply(ind_cases "y>a'{y}.(P  Q')  ay>  P'")
            apply(simp add: pi.inject alpha' residual.inject abs_fresh eqvts calc_atm)
            apply(auto elim: outputCases)
            apply(simp add: pi.inject residual.inject alpha' calc_atm)
            apply auto
            apply(ind_cases "y>a'{y}.(P  Q')  ay>  P'")
            apply(auto simp add: pi.inject alpha' residual.inject abs_fresh eqvts calc_atm)
            apply(auto elim: outputCases)
            apply(erule_tac outputCases)
            apply(auto simp add: freeRes.inject)
            apply hypsubst_thin
            apply(drule_tac pi="[(b, y)]" in pt_bij3)
            by simp
        with PQTrans show ?thesis by simp
      qed
    }
    moreover assume "R ax>  P'"
    with Exp obtain R where "R  expandSet P Q" and "R ax>  P'" 
      apply(drule_tac expandAction') by auto
    moreover obtain y::name where "y  P" and "y  Q" and "y  R" and "y  P'"
      by(generate_fresh "name") auto
    moreover with y  P' R ax>  P' have "R ay>  ([(x, y)]  P')" by(simp add: alphaBoundResidual)
    ultimately have "P  Q ay>  ([(x, y)]  P')" by auto
    thus "P  Q ax>  P'" using y  P' by(simp add: alphaBoundResidual)
    qed
  qed

  obtain y where yineqx: "a  y" and yFreshP': "y  P'"
    by(force intro: name_exists_fresh[of "(a, P')"] simp add: fresh_prod)
  from Exp Phnf Qhnf yineqx have "(P  Q ay>  [(x, y)]  P') = (R ay>  [(x, y)]  P')"
    by(rule Goal)
  moreover with yFreshP' have "x  [(x, y)]  P'" by(simp add: name_fresh_left name_calc)
  ultimately show "(P  Q ax>  P') = (R ax>  P')"
    by(simp add: alphaBoundResidual name_swap)
qed

lemma expandLeft:
  fixes P   :: pi
  and   Q   :: pi
  and   R   :: pi
  and   Rel :: "(pi × pi) set"

  assumes Exp: "(R, expandSet P Q)  sumComposeSet"
  and     Phnf: "hnf P"
  and     Qhnf: "hnf Q"
  and     Id: "Id  Rel"

  shows "P  Q ↝[Rel] R"
proof(induct rule: simCases)
  case(Bound a x R')
  have "R a«x»  R'" by fact
  with Exp Phnf Qhnf have "P  Q a«x»  R'" by(cases a, auto simp add: expandTrans)
  moreover from Id have "derivative R' R' a x Rel" by(cases a, auto simp add: derivative_def)
  ultimately show ?case by blast
next
  case(Free α R')
  have "R α  R'" by fact
  with Exp Phnf Qhnf have "P  Q α  R'" by(cases α, auto simp add: expandTrans)
  moreover from Id have "(R', R')  Rel" by blast
  ultimately show ?case by blast
qed

lemma expandRight:
  fixes P   :: pi
  and   Q   :: pi
  and   R   :: pi
  and   Rel :: "(pi × pi) set"

  assumes Exp: "(R, expandSet P Q)  sumComposeSet"
  and     Phnf: "hnf P"
  and     Qhnf: "hnf Q"
  and     Id: "Id  Rel"

  shows "R ↝[Rel] P  Q"
proof(induct rule: simCases)
  case(Bound a x R')
  have "P  Q a«x»  R'" by fact
  with Exp Phnf Qhnf have "R a«x»  R'" by(cases a, auto simp add: expandTrans)
  moreover from Id have "derivative R' R' a x Rel" by(cases a, auto simp add: derivative_def)
  ultimately show ?case by blast
next
  case(Free α R')
  have "P  Q α  R'" by fact
  with Exp Phnf Qhnf have "R α  R'" by(cases α, auto simp add: expandTrans)
  moreover from Id have "(R', R')  Rel" by blast
  ultimately show ?case by blast
qed

lemma expandSC: 
  fixes P :: pi
  and   Q :: pi
  and   R :: pi
  
  assumes "(R, expandSet P Q)  sumComposeSet"
  and     "hnf P"
  and     "hnf Q"

  shows "P  Q  R"
proof -
  let ?X = "{(P  Q, R) | P Q R. (R, expandSet P Q)  sumComposeSet  hnf P  hnf Q}  {(R, P  Q) | P Q R. (R, expandSet P Q)  sumComposeSet  hnf P  hnf Q}"
  from assms have "(P  Q, R)  ?X" by auto
  thus ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cSim P Q)
    thus ?case
      by(blast intro: reflexive expandLeft expandRight)
  next
    case(cSym P Q)
     thus ?case by auto
   qed
 qed

end