Theory Bisim_Pres

(* 
   Title: Psi-calculi   
   Author/Maintainer: Jesper Bengtson (jebe@itu.dk), 2012
*)
theory Bisim_Pres
  imports Bisimulation Sim_Pres
begin

context env begin

lemma bisimInputPres:
  fixes Ψ    :: 'b
  and   P    :: "('a, 'b, 'c) psi"
  and   Q    :: "('a, 'b, 'c) psi"
  and   M    :: 'a
  and   xvec :: "name list"
  and   N    :: 'a

  assumes "⋀Tvec. length xvec = length Tvec ⟹ Ψ ⊳ P[xvec::=Tvec] ∼ Q[xvec::=Tvec]"

  shows "Ψ ⊳ M⦇λ*xvec N⦈.P ∼ M⦇λ*xvec N⦈.Q"
proof -
  let ?X = "{(Ψ, M⦇λ*xvec N⦈.P, M⦇λ*xvec N⦈.Q) | Ψ M xvec N P Q. ∀Tvec. length xvec = length Tvec ⟶ Ψ ⊳ P[xvec::=Tvec] ∼ Q[xvec::=Tvec]}"

  from assms have "(Ψ, M⦇λ*xvec N⦈.P, M⦇λ*xvec N⦈.Q) ∈ ?X" by blast
  thus ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ P Q)
    thus ?case by auto
  next
    case(cSim Ψ P Q)
    thus ?case by(blast intro: inputPres)
  next
    case(cExt Ψ P Q Ψ')
    thus ?case by(blast dest: bisimE)
  next
    case(cSym Ψ P Q)
    thus ?case by(blast dest: bisimE)
  qed
qed
  
lemma bisimOutputPres:
  fixes Ψ :: 'b
  and   P :: "('a, 'b, 'c) psi"
  and   Q :: "('a, 'b, 'c) psi"
  and   M :: 'a
  and   N :: 'a

  assumes "Ψ ⊳ P ∼ Q"

  shows "Ψ ⊳ M⟨N⟩.P ∼ M⟨N⟩.Q"
proof -
  let ?X = "{(Ψ, M⟨N⟩.P, M⟨N⟩.Q) | Ψ M N P Q. Ψ ⊳ P ∼ Q}"
  from ‹Ψ ⊳ P ∼ Q› have "(Ψ, M⟨N⟩.P, M⟨N⟩.Q) ∈ ?X" by auto
  thus ?thesis
    by(coinduct rule: bisimCoinduct, auto) (blast intro: outputPres dest: bisimE)+
qed

lemma bisimCasePres:
  fixes Ψ   :: 'b
  and   CsP :: "('c × ('a, 'b, 'c) psi) list"
  and   CsQ :: "('c × ('a, 'b, 'c) psi) list"

  assumes "⋀φ P. (φ, P) mem CsP ⟹ ∃Q. (φ, Q) mem CsQ ∧ guarded Q ∧ Ψ ⊳ P ∼ Q"
  and     "⋀φ Q. (φ, Q) mem CsQ ⟹ ∃P. (φ, P) mem CsP ∧ guarded P ∧ Ψ ⊳ P ∼ Q"

  shows "Ψ ⊳ Cases CsP ∼ Cases CsQ"
proof -
  let ?X = "{(Ψ, Cases CsP, Cases CsQ) | Ψ CsP CsQ. (∀φ P. (φ, P) mem CsP ⟶ (∃Q. (φ, Q) mem CsQ ∧ guarded Q ∧ Ψ ⊳ P ∼ Q)) ∧
                                                     (∀φ Q. (φ, Q) mem CsQ ⟶ (∃P. (φ, P) mem CsP ∧ guarded P ∧ Ψ ⊳ P ∼ Q))}"
  from assms have "(Ψ, Cases CsP, Cases CsQ) ∈ ?X" by auto
  thus ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ P Q)
    thus ?case by auto
  next
    case(cSim Ψ CasesP CasesQ)
    then obtain CsP CsQ where C1: "⋀φ Q. (φ, Q) mem CsQ ⟹ ∃P. (φ, P) mem CsP ∧ guarded P ∧ Ψ ⊳ P ∼ Q"
                          and A: "CasesP = Cases CsP" and B: "CasesQ = Cases CsQ"
      by auto
    note C1
    moreover have "⋀Ψ P Q. Ψ ⊳ P ∼ Q ⟹ Ψ ⊳ P ↝[bisim] Q" by(rule bisimE)
    moreover have "bisim ⊆ ?X ∪ bisim" by blast
    ultimately have "Ψ ⊳ Cases CsP ↝[(?X ∪ bisim)] Cases CsQ"
      by(rule casePres)
    thus ?case using A B by blast
  next
    case(cExt Ψ P Q)
    thus ?case by(blast dest: bisimE)
  next
    case(cSym Ψ P Q)
    thus ?case by(blast dest: bisimE)
  qed
qed

lemma bisimResPres:
  fixes Ψ :: 'b
  and   P :: "('a, 'b, 'c) psi"
  and   Q :: "('a, 'b, 'c) psi"
  and   x :: name
  
  assumes "Ψ ⊳ P ∼ Q"
  and     "x ♯ Ψ"

  shows "Ψ ⊳ ⦇νx⦈P ∼ ⦇νx⦈Q"
proof -
  let ?X = "{(Ψ, ⦇νx⦈P, ⦇νx⦈Q) | Ψ x P Q. Ψ ⊳ P ∼ Q ∧ x ♯ Ψ}"
  
  from assms have "(Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X" by auto
  thus ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ xP xQ)
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain x P Q where "Ψ ⊳ P ∼ Q" and "x ♯ Ψ" and "xP = ⦇νx⦈P" and "xQ = ⦇νx⦈Q"
      by auto
    moreover from ‹Ψ ⊳ P ∼ Q› have PeqQ: "insertAssertion(extractFrame P) Ψ ≃F insertAssertion(extractFrame Q) Ψ"
      by(rule bisimE)
    ultimately show ?case by(auto intro: frameResPres)
  next
    case(cSim Ψ xP xQ)
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain x P Q where "Ψ ⊳ P ∼ Q" and "x ♯ Ψ" and "xP = ⦇νx⦈P" and "xQ = ⦇νx⦈Q"
      by auto
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊳ P ↝[bisim] Q" by(rule bisimE)
    moreover have "eqvt ?X"
      by(force simp add: eqvt_def bisimClosed pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
    hence "eqvt(?X ∪ bisim)" by auto
    moreover note ‹x ♯ Ψ›
    moreover have "bisim ⊆ ?X ∪ bisim" by auto
    moreover have "⋀Ψ P Q x. ⟦(Ψ, P, Q) ∈ bisim; x ♯ Ψ⟧ ⟹ (Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X ∪ bisim"
      by auto
    ultimately have "Ψ ⊳ ⦇νx⦈P ↝[(?X ∪ bisim)] ⦇νx⦈Q"
      by(rule resPres)
    with ‹xP = ⦇νx⦈P› ‹xQ = ⦇νx⦈Q› show ?case
      by simp
  next
    case(cExt Ψ xP xQ Ψ')
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain x P Q where "Ψ ⊳ P ∼ Q" and "x ♯ Ψ" and "xP = ⦇νx⦈P" and "xQ = ⦇νx⦈Q"
      by auto
    obtain y::name where "y ♯ P" and "y ♯ Q" and "y ♯ Ψ" and "y ♯ Ψ'"
     by(generate_fresh "name", auto simp add: fresh_prod)
   from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊗ ([(x, y)] ∙ Ψ') ⊳ P ∼ Q"
     by(rule bisimE)
   hence "([(x, y)] ∙ (Ψ ⊗ ([(x, y)] ∙ Ψ'))) ⊳ ([(x, y)] ∙ P) ∼ ([(x, y)] ∙ Q)"
     by(rule bisimClosed)
   with ‹x ♯ Ψ› ‹y ♯ Ψ› have "Ψ ⊗ Ψ' ⊳ ([(x, y)] ∙ P) ∼ ([(x, y)] ∙ Q)"
     by(simp add: eqvts)
   with ‹y ♯ Ψ› ‹y ♯ Ψ'› have "(Ψ ⊗ Ψ', ⦇νy⦈([(x, y)] ∙ P), ⦇νy⦈([(x, y)] ∙ Q)) ∈ ?X"
     by auto
   moreover from ‹y ♯ P› ‹y ♯ Q› have "⦇νx⦈P = ⦇νy⦈([(x, y)] ∙ P)" and "⦇νx⦈Q = ⦇νy⦈([(x, y)] ∙ Q)"
     by(simp add: alphaRes)+
   ultimately show ?case using ‹xP = ⦇νx⦈P› ‹xQ = ⦇νx⦈Q› by simp
 next
    case(cSym Ψ P Q)
    thus ?case
      by(blast dest: bisimE)
  qed
qed

lemma bisimResChainPres:
  fixes Ψ   :: 'b
  and   P    :: "('a, 'b, 'c) psi"
  and   Q    :: "('a, 'b, 'c) psi"
  and   xvec :: "name list"

  assumes "Ψ ⊳ P ∼ Q"
  and     "xvec ♯* Ψ"

  shows "Ψ ⊳ ⦇ν*xvec⦈P ∼ ⦇ν*xvec⦈Q"
using assms
by(induct xvec) (auto intro: bisimResPres)

lemma bisimParPresAux:
  fixes Ψ  :: 'b
  and   ΨR :: 'b
  and   P  :: "('a, 'b, 'c) psi"
  and   Q  :: "('a, 'b, 'c) psi"
  and   R  :: "('a, 'b, 'c) psi"
  and   AR :: "name list"
  
  assumes "Ψ ⊗ ΨR ⊳ P ∼ Q"
  and     FrR: "extractFrame R = ⟨AR, ΨR⟩"
  and     "AR ♯* Ψ"
  and     "AR ♯* P"
  and     "AR ♯* Q"

  shows "Ψ ⊳ P ∥ R ∼ Q ∥ R"
proof -
  let ?X = "{(Ψ, ⦇ν*xvec⦈(P ∥ R), ⦇ν*xvec⦈(Q ∥ R)) | xvec Ψ P Q R. xvec ♯* Ψ ∧ (∀AR ΨR. (extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* Ψ ∧ AR ♯* P ∧ AR ♯* Q) ⟶
                                                                                          Ψ ⊗ ΨR ⊳ P ∼ Q)}"
  {
    fix xvec :: "name list"
    and Ψ    :: 'b 
    and P    :: "('a, 'b, 'c) psi"
    and Q    :: "('a, 'b, 'c) psi"
    and R    :: "('a, 'b, 'c) psi"

    assume "xvec ♯* Ψ"
    and    "⋀AR ΨR. ⟦extractFrame R = ⟨AR, ΨR⟩; AR ♯* Ψ; AR ♯* P; AR ♯* Q⟧ ⟹ Ψ ⊗ ΨR ⊳ P ∼ Q"

    hence "(Ψ, ⦇ν*xvec⦈(P ∥ R), ⦇ν*xvec⦈(Q ∥ R)) ∈ ?X"
      apply auto
      by blast
  }

  note XI = this
  {
    fix xvec :: "name list"
    and Ψ    :: 'b 
    and P    :: "('a, 'b, 'c) psi"
    and Q    :: "('a, 'b, 'c) psi"
    and R    :: "('a, 'b, 'c) psi"
    and C    :: "'d::fs_name"

    assume "xvec ♯* Ψ"
    and    A: "⋀AR ΨR. ⟦extractFrame R = ⟨AR, ΨR⟩; AR ♯* Ψ; AR ♯* P; AR ♯* Q; AR ♯* C⟧ ⟹ Ψ ⊗ ΨR ⊳ P ∼ Q"

    from ‹xvec ♯* Ψ› have "(Ψ, ⦇ν*xvec⦈(P ∥ R), ⦇ν*xvec⦈(Q ∥ R)) ∈ ?X"
    proof(rule XI)
      fix AR ΨR
      assume FrR: "extractFrame R = ⟨AR, ΨR⟩"
      obtain p::"name prm" where "(p ∙ AR) ♯* Ψ" and "(p ∙ AR) ♯* P" and "(p ∙ AR) ♯* Q" and "(p ∙ AR) ♯* R" and "(p ∙ AR) ♯* C"
                             and "(p ∙ AR) ♯* ΨR" and S: "(set p) ⊆ (set AR) × (set(p ∙ AR))" and "distinctPerm p"
        by(rule_tac c="(Ψ, P, Q, R, ΨR, C)" in name_list_avoiding) auto
      from FrR ‹(p ∙ AR) ♯* ΨR› S have "extractFrame R = ⟨(p ∙ AR), p ∙ ΨR⟩" by(simp add: frameChainAlpha')

      moreover assume "AR ♯* Ψ"
      hence "(p ∙ AR) ♯* (p ∙ Ψ)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹AR ♯* Ψ› ‹(p ∙ AR) ♯* Ψ› S have "(p ∙ AR) ♯* Ψ" by simp
      moreover assume "AR ♯* P"
      hence "(p ∙ AR) ♯* (p ∙ P)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹AR ♯* P› ‹(p ∙ AR) ♯* P› S have "(p ∙ AR) ♯* P" by simp
      moreover assume "AR ♯* Q"
      hence "(p ∙ AR) ♯* (p ∙ Q)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹AR ♯* Q› ‹(p ∙ AR) ♯* Q› S have "(p ∙ AR) ♯* Q" by simp
      ultimately have "Ψ ⊗ (p ∙ ΨR) ⊳ P ∼ Q" using ‹(p ∙ AR) ♯* C› A by blast
      hence "(p ∙ (Ψ ⊗ (p ∙ ΨR))) ⊳ (p ∙ P) ∼ (p ∙ Q)" by(rule bisimClosed)
      with ‹AR ♯* Ψ› ‹(p ∙ AR) ♯* Ψ› ‹AR ♯* P› ‹(p ∙ AR) ♯* P› ‹AR ♯* Q› ‹(p ∙ AR) ♯* Q› S ‹distinctPerm p›
      show "Ψ ⊗ ΨR ⊳ P ∼ Q" by(simp add: eqvts)
    qed
  }
  note XI' = this

  have "eqvt ?X"
    apply(auto simp add: eqvt_def)
    apply(rule_tac x="p ∙ xvec" in exI)
    apply(rule_tac x="p ∙ P" in exI)
    apply(rule_tac x="p ∙ Q" in exI)
    apply(rule_tac x="p ∙ R" in exI)
    apply(simp add: eqvts)
    apply(simp add: fresh_star_bij)
    apply(clarify)
    apply(erule_tac x="(rev p) ∙ AR" in allE)
    apply(erule_tac x="(rev p) ∙ ΨR" in allE)
    apply(drule mp)
    apply(rule conjI)
    apply(rule_tac pi=p in pt_bij4[OF pt_name_inst, OF at_name_inst])
    apply(simp add: eqvts)
    defer
    apply(drule_tac p=p in bisimClosed)
    apply(simp add: eqvts)
    apply(subst pt_fresh_star_bij[OF pt_name_inst,OF at_name_inst, of p, THEN sym])
    apply simp
    apply(subst pt_fresh_star_bij[OF pt_name_inst,OF at_name_inst, of p, THEN sym])
    apply simp
    apply(subst pt_fresh_star_bij[OF pt_name_inst,OF at_name_inst, of p, THEN sym])
    by simp

  moreover have Res: "⋀Ψ P Q x. ⟦(Ψ, P, Q) ∈ ?X ∪ bisim; x ♯ Ψ⟧ ⟹ (Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X ∪ bisim"
  proof -
    fix Ψ P Q x
    assume "(Ψ, P, Q) ∈ ?X ∪ bisim" and "(x::name) ♯ Ψ"
    show "(Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X ∪ bisim"
    proof(case_tac "(Ψ, P, Q) ∈ ?X")
      assume "(Ψ, P, Q) ∈ ?X"
      with ‹x ♯ Ψ› have "(Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X"
        apply auto
        by(rule_tac x="x#xvec" in exI) auto
      thus ?thesis by simp
    next
      assume "¬(Ψ, P, Q) ∈ ?X"
      with ‹(Ψ, P, Q) ∈ ?X ∪ bisim› have "Ψ ⊳ P ∼ Q"
        by blast
      hence "Ψ ⊳ ⦇νx⦈P ∼ ⦇νx⦈Q" using ‹x ♯ Ψ›
        by(rule bisimResPres)
      thus ?thesis
        by simp
    qed
  qed

  have "(Ψ, P ∥ R, Q ∥ R) ∈ ?X" 
  proof -
    {
      fix AR' :: "name list"
      and ΨR' :: 'b

      assume FrR': "extractFrame R = ⟨AR', ΨR'⟩"
      and    "AR' ♯* Ψ"
      and    "AR' ♯* P"
      and    "AR' ♯* Q"

      obtain p where "(p ∙ AR') ♯* AR" and "(p ∙ AR') ♯* ΨR'" and "(p ∙ AR') ♯* Ψ" and "(p ∙ AR') ♯* P" and "(p ∙ AR') ♯* Q"
                 and Sp: "(set p) ⊆ (set AR') × (set(p ∙ AR'))" and "distinctPerm p"
        by(rule_tac c="(AR, Ψ, ΨR', P, Q)" in name_list_avoiding) auto
            
      from FrR' ‹(p ∙ AR') ♯*  ΨR'› Sp have "extractFrame R = ⟨(p ∙ AR'), p ∙ ΨR'⟩"
        by(simp add: frameChainAlpha eqvts)
      with FrR ‹(p ∙ AR') ♯* AR› obtain q::"name prm" 
        where Sq: "set q ⊆ set(p ∙ AR') × set AR" and "distinctPerm q" and "ΨR = q ∙ p ∙ ΨR'"
        by(force elim: frameChainEq)

      from ‹Ψ ⊗ ΨR ⊳ P ∼ Q› ‹ΨR = q ∙ p ∙ ΨR'› have "Ψ ⊗ (q ∙ p ∙ ΨR') ⊳ P ∼ Q" by simp
      hence "(q ∙ (Ψ ⊗ (q ∙ p ∙ ΨR'))) ⊳ (q ∙ P) ∼ (q ∙ Q)" by(rule bisimClosed)
      with Sq ‹AR ♯* Ψ› ‹(p ∙ AR') ♯* Ψ› ‹AR ♯* P› ‹(p ∙ AR') ♯* P› ‹AR ♯* Q› ‹(p ∙ AR') ♯* Q› ‹distinctPerm q›
      have "Ψ ⊗ (p ∙ ΨR') ⊳ P ∼ Q" by(simp add: eqvts)
      hence "(p ∙ (Ψ ⊗ (p ∙ ΨR'))) ⊳ (p ∙ P) ∼ (p ∙ Q)" by(rule bisimClosed)
      with Sp ‹AR' ♯* Ψ› ‹(p ∙ AR') ♯* Ψ› ‹AR' ♯* P› ‹(p ∙ AR') ♯* P› ‹AR' ♯* Q› ‹(p ∙ AR') ♯* Q› ‹distinctPerm p›
      have "Ψ ⊗ ΨR' ⊳ P ∼ Q" by(simp add: eqvts)
    }
    thus ?thesis
      apply auto
      apply(rule_tac x="[]" in exI)
      by auto blast
  qed
  thus ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ PR QR)
    from ‹(Ψ, PR, QR) ∈ ?X›
    obtain xvec P Q R AR ΨR where PFrR: "PR = ⦇ν*xvec⦈(P ∥ R)" and QFrR: "QR = ⦇ν*xvec⦈(Q ∥ R)"
                              and "xvec ♯* Ψ" and FrR: "extractFrame R = ⟨AR, ΨR⟩" and PSimQ: "Ψ ⊗ ΨR ⊳ P ∼ Q"
                              and "AR ♯* xvec" and "AR ♯* Ψ" and "AR ♯* P" and "AR ♯* Q" and "AR ♯* R"
      apply auto
      apply(subgoal_tac "∃AR ΨR. extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* (xvec, Ψ, P, Q, R)")
      apply auto
      apply(rule_tac F="extractFrame R" and C="(xvec, Ψ, P, Q, R)" in freshFrame)
      by auto

    obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "AP ♯* AR" and "AP ♯* ΨR"
      by(rule_tac C="(Ψ, AR, ΨR)" in freshFrame) auto
    obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* AR" and "AQ ♯* ΨR"
      by(rule_tac C="(Ψ, AR, ΨR)" in freshFrame) auto
    from ‹AR ♯* P› ‹AR ♯* Q› ‹AP ♯* AR› ‹AQ ♯* AR› FrP FrQ have "AR ♯* ΨP" and  "AR ♯* ΨQ"
      by(force dest: extractFrameFreshChain)+
    
    have "⟨(AP@AR), Ψ ⊗ ΨP ⊗ ΨR⟩ ≃F ⟨(AQ@AR), Ψ ⊗ ΨQ ⊗ ΨR⟩"
    proof -
      have "⟨AP, Ψ ⊗ ΨP ⊗ ΨR⟩ ≃F ⟨AP, (Ψ ⊗ ΨR) ⊗ ΨP⟩"
        by(metis frameResChainPres frameNilStatEq Associativity Commutativity AssertionStatEqTrans Composition)
      moreover from PSimQ have "insertAssertion(extractFrame P) (Ψ ⊗ ΨR) ≃F insertAssertion(extractFrame Q) (Ψ ⊗ ΨR)"
        by(rule bisimE)
      with FrP FrQ freshCompChain ‹AP ♯* Ψ› ‹AP ♯* ΨR› ‹AQ ♯* Ψ› ‹AQ ♯* ΨR› have "⟨AP, (Ψ ⊗ ΨR) ⊗ ΨP⟩ ≃F ⟨AQ, (Ψ ⊗ ΨR) ⊗ ΨQ⟩"
        by auto
      moreover have "⟨AQ, (Ψ ⊗ ΨR) ⊗ ΨQ⟩ ≃F ⟨AQ, Ψ ⊗ ΨQ ⊗ ΨR⟩"
        by(metis frameResChainPres frameNilStatEq Associativity Commutativity AssertionStatEqTrans Composition)
      ultimately have "⟨AP, Ψ ⊗ ΨP ⊗ ΨR⟩ ≃F ⟨AQ, Ψ ⊗ ΨQ ⊗ ΨR⟩"
        by(blast intro: FrameStatEqTrans)
      hence "⟨(AR@AP), Ψ ⊗ ΨP ⊗ ΨR⟩ ≃F ⟨(AR@AQ), Ψ ⊗ ΨQ ⊗ ΨR⟩"
        by(drule_tac frameResChainPres) (simp add: frameChainAppend)
      thus ?thesis
        apply(simp add: frameChainAppend)
        by(metis frameResChainComm FrameStatEqTrans)
    qed
    moreover from ‹AP ♯* Ψ› ‹AR ♯* Ψ› have "(AP@AR) ♯* Ψ" by simp
    moreover from ‹AQ ♯* Ψ› ‹AR ♯* Ψ› have "(AQ@AR) ♯* Ψ" by simp
    ultimately have PFrRQR: "insertAssertion(extractFrame(P ∥ R)) Ψ ≃F insertAssertion(extractFrame(Q ∥ R)) Ψ"
      using FrP FrQ FrR ‹AP ♯* AR› ‹AP ♯* ΨR› ‹AQ ♯* AR› ‹AQ ♯* ΨR› ‹AR ♯* ΨP› ‹AR ♯* ΨQ›
      by simp
      
    from ‹xvec ♯* Ψ› have "insertAssertion (extractFrame(⦇ν*xvec⦈P ∥ R)) Ψ ≃F ⦇ν*xvec⦈(insertAssertion (extractFrame(P ∥ R)) Ψ)"
      by(rule insertAssertionExtractFrameFresh)
    moreover from PFrRQR have "⦇ν*xvec⦈(insertAssertion (extractFrame(P ∥ R)) Ψ) ≃F ⦇ν*xvec⦈(insertAssertion (extractFrame(Q ∥ R)) Ψ)"
      by(induct xvec) (auto intro: frameResPres)
    moreover from ‹xvec ♯* Ψ› have "⦇ν*xvec⦈(insertAssertion (extractFrame(Q ∥ R)) Ψ) ≃F insertAssertion (extractFrame(⦇ν*xvec⦈Q ∥ R)) Ψ"
      by(rule FrameStatEqSym[OF insertAssertionExtractFrameFresh])
    ultimately show ?case using PFrR QFrR
      by(blast intro: FrameStatEqTrans)
  next
    case(cSim Ψ PR QR)
    {
      fix Ψ P Q R xvec
      assume "⋀AR ΨR. ⟦extractFrame R = ⟨AR, ΨR⟩; AR ♯* Ψ; AR ♯* P; AR ♯* Q⟧ ⟹ Ψ ⊗ ΨR ⊳ P ∼ Q"
      moreover have "eqvt bisim" by simp
      moreover from ‹eqvt ?X› have "eqvt(?X ∪ bisim)" by auto
      moreover from bisimE(1) have "⋀Ψ P Q. Ψ ⊳ P ∼ Q ⟹ insertAssertion (extractFrame Q) Ψ ↪F insertAssertion (extractFrame P) Ψ" by(simp add: FrameStatEq_def)
      moreover note bisimE(2) bisimE(3)
      moreover 
      {
        fix Ψ P Q AR ΨR R
        assume PSimQ: "Ψ ⊗ ΨR ⊳ P ∼ Q"
           and FrR: "extractFrame R = ⟨AR, ΨR⟩"
           and "AR ♯* Ψ"
           and "AR ♯* P"
           and "AR ♯* Q"
        hence "(Ψ, P ∥ R, Q ∥ R) ∈ ?X"
        proof -
          have "P ∥ R = ⦇ν*[]⦈(P ∥ R)" by simp
          moreover have "Q ∥ R = ⦇ν*[]⦈(Q ∥ R)" by simp
          moreover have "([]::name list) ♯* Ψ" by simp
          moreover 
          {
            fix AR' ΨR'

            assume FrR': "extractFrame R = ⟨AR', ΨR'⟩"
               and "AR' ♯* Ψ"
               and "AR' ♯* P"
               and "AR' ♯* Q"
            obtain p where "(p ∙ AR') ♯* AR"
                       and "(p ∙ AR') ♯* ΨR'"
                       and "(p ∙ AR') ♯* Ψ"
                       and "(p ∙ AR') ♯* P"
                       and "(p ∙ AR') ♯* Q"
                       and S: "(set p) ⊆ (set AR') × (set(p ∙ AR'))" and "distinctPerm p"
              by(rule_tac c="(AR, Ψ, ΨR', P, Q)" in name_list_avoiding) auto


            from ‹(p ∙ AR') ♯* ΨR'› S have "⟨AR', ΨR'⟩ = ⟨p ∙ AR', p ∙ ΨR'⟩"
              by(simp add: frameChainAlpha)

            with FrR' have FrR'': "extractFrame R = ⟨p ∙ AR', p ∙ ΨR'⟩" by simp
            with FrR ‹(p ∙ AR') ♯* AR›
            obtain q where "p ∙ ΨR' = (q::name prm) ∙ ΨR" and S': "set q ⊆ (set AR) × set(p ∙ AR')" and "distinctPerm q"
              apply auto
              apply(drule_tac sym) apply simp
              by(drule_tac frameChainEq) auto
            from PSimQ have "(q ∙ (Ψ ⊗ ΨR)) ⊳ (q ∙ P) ∼ (q ∙ Q)"
              by(rule bisimClosed)
            with ‹AR ♯* Ψ› ‹AR ♯* P› ‹AR ♯* Q› ‹(p ∙ AR') ♯* Ψ› ‹(p ∙ AR') ♯* P› ‹(p ∙ AR') ♯* Q› S'
            have "Ψ ⊗ (q ∙ ΨR) ⊳ P ∼ Q" by(simp add: eqvts)
            hence "(p ∙ (Ψ ⊗ (q ∙ ΨR))) ⊳ (p ∙ P) ∼ (p ∙ Q)" by(rule bisimClosed)
            with ‹AR' ♯* Ψ› ‹AR' ♯* P› ‹AR' ♯* Q› ‹(p ∙ AR') ♯* Ψ› ‹(p ∙ AR') ♯* P› ‹(p ∙ AR') ♯* Q› S ‹distinctPerm p› ‹(p ∙ ΨR') = q ∙ ΨR› 
            have "Ψ ⊗ ΨR' ⊳ P ∼ Q"
              by(drule_tac sym) (simp add: eqvts)
          }
          ultimately show ?thesis
            by blast
        qed
        hence "(Ψ, P ∥ R, Q ∥ R) ∈ ?X ∪ bisim"
          by simp
      }
      moreover have "⋀Ψ P Q xvec. ⟦(Ψ, P, Q) ∈ ?X ∪ bisim; (xvec::name list) ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
      proof -
        fix Ψ P Q xvec
        assume "(Ψ, P, Q) ∈ ?X ∪ bisim"
        assume "(xvec::name list) ♯* Ψ"
        thus "(Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
        proof(induct xvec)
          case Nil
          thus ?case using ‹(Ψ, P, Q) ∈ ?X ∪ bisim› by simp
        next
          case(Cons x xvec)
          thus ?case by(simp only: resChain.simps) (rule_tac Res, auto)
        qed
      qed
      ultimately have "Ψ ⊳ P ∥ R ↝[(?X ∪ bisim)] Q ∥ R" using statEqBisim
        by(rule parPres)
      moreover assume "(xvec::name list) ♯* Ψ"
      moreover from ‹eqvt ?X› have "eqvt(?X ∪ bisim)" by auto
      ultimately have "Ψ ⊳ ⦇ν*xvec⦈(P ∥ R) ↝[(?X ∪ bisim)] ⦇ν*xvec⦈(Q ∥ R)" using Res
        by(rule_tac resChainPres)
    }
    with ‹(Ψ, PR, QR) ∈ ?X› show ?case by blast
  next
    case(cExt Ψ PR QR Ψ')

    from ‹(Ψ, PR, QR) ∈ ?X›
    obtain xvec P Q R AR ΨR where PFrR: "PR = ⦇ν*xvec⦈(P ∥ R)" and QFrR: "QR = ⦇ν*xvec⦈(Q ∥ R)"
                               and "xvec ♯* Ψ" and A: "∀AR ΨR. (extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* Ψ ∧ AR ♯* P ∧ AR ♯* Q) ⟶ Ψ ⊗ ΨR ⊳ P ∼ Q"
      by auto
    
    obtain p where "(p ∙ xvec) ♯* Ψ"
               and "(p ∙ xvec) ♯* P"
               and "(p ∙ xvec) ♯* Q"
               and "(p ∙ xvec) ♯* R"
               and "(p ∙ xvec) ♯* Ψ'"
               and S: "(set p) ⊆ (set xvec) × (set(p ∙ xvec))" and "distinctPerm p"
      by(rule_tac c="(Ψ, P, Q, R, Ψ')" in name_list_avoiding) auto

    from ‹(p ∙ xvec) ♯* P› ‹(p ∙ xvec) ♯* R› S have "⦇ν*xvec⦈(P ∥ R) = ⦇ν*(p ∙ xvec)⦈(p ∙ (P ∥ R))"
      by(subst resChainAlpha) auto
    hence PRAlpha: "⦇ν*xvec⦈(P ∥ R) = ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ (p ∙ R))"
      by(simp add: eqvts)

    from ‹(p ∙ xvec) ♯* Q› ‹(p ∙ xvec) ♯* R› S have "⦇ν*xvec⦈(Q ∥ R) = ⦇ν*(p ∙ xvec)⦈(p ∙ (Q ∥ R))"
      by(subst resChainAlpha) auto
    hence QRAlpha: "⦇ν*xvec⦈(Q ∥ R) = ⦇ν*(p ∙ xvec)⦈((p ∙ Q) ∥ (p ∙ R))"
      by(simp add: eqvts)

    from ‹(p ∙ xvec) ♯* Ψ› ‹(p ∙ xvec) ♯* Ψ'› have "(Ψ ⊗ Ψ', ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ (p ∙ R)), ⦇ν*(p ∙ xvec)⦈((p ∙ Q) ∥ (p ∙ R))) ∈ ?X"
    proof(rule_tac C2="(Ψ, (p ∙ P), (p ∙ Q), R, Ψ', xvec, p ∙ xvec)" in XI', auto)
      fix AR ΨR
      assume FrR: "extractFrame (p ∙ R) = ⟨AR, ΨR⟩" and "AR ♯* Ψ" and "AR ♯* Ψ'" and "AR ♯* (p ∙ P)" and "AR ♯* (p ∙ Q)"
      from FrR have "(p ∙ (extractFrame (p ∙ R))) = (p ∙ ⟨AR, ΨR⟩)" by simp
      with ‹distinctPerm p› have "extractFrame R = ⟨p ∙ AR, p ∙ ΨR⟩" by(simp add: eqvts)
      moreover from ‹AR ♯* Ψ› have "(p ∙ AR) ♯* (p ∙ Ψ)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹xvec ♯* Ψ› ‹(p ∙ xvec) ♯* Ψ› S have "(p ∙ AR) ♯* Ψ" by simp
      moreover from ‹AR ♯* (p ∙ P)› have "(p ∙ AR) ♯* (p ∙ p ∙ P)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹distinctPerm p› have "(p ∙ AR) ♯* P" by simp
      moreover from ‹AR ♯* (p ∙ Q)› have "(p ∙ AR) ♯* (p ∙ p ∙ Q)" by(simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst])
      with ‹distinctPerm p› have "(p ∙ AR) ♯* Q" by simp
      ultimately have "Ψ ⊗ (p ∙ ΨR) ⊳ P ∼ Q" using A by blast
      hence "(Ψ ⊗ (p ∙ ΨR)) ⊗ (p ∙ Ψ') ⊳ P ∼ Q" by(rule bisimE)
      moreover have "(Ψ ⊗ (p ∙ ΨR)) ⊗ (p ∙ Ψ') ≃ (Ψ ⊗ (p ∙ Ψ')) ⊗ (p ∙ ΨR)"
        by(metis Associativity Commutativity Composition AssertionStatEqTrans AssertionStatEqSym)
      ultimately have "(Ψ ⊗ (p ∙ Ψ')) ⊗ (p ∙ ΨR) ⊳ P ∼ Q" 
        by(rule statEqBisim)
      hence "(p ∙ ((Ψ ⊗ (p ∙ Ψ')) ⊗ (p ∙ ΨR))) ⊳ (p ∙ P) ∼ (p ∙ Q)"
        by(rule bisimClosed)
      with ‹distinctPerm p› ‹xvec ♯* Ψ› ‹(p ∙ xvec) ♯* Ψ› S show "(Ψ ⊗ Ψ') ⊗ ΨR ⊳ (p ∙ P) ∼ (p ∙ Q)"
        by(simp add: eqvts)
    qed
    with PFrR QFrR PRAlpha QRAlpha show ?case by simp
  next
    case(cSym Ψ PR QR)
    thus ?case by(blast dest: bisimE)
  qed
qed

lemma bisimParPres:
  fixes Ψ :: 'b
  and   P :: "('a, 'b, 'c) psi"
  and   Q :: "('a, 'b, 'c) psi"
  and   R :: "('a, 'b, 'c) psi"
  
  assumes "Ψ ⊳ P ∼ Q"

  shows "Ψ ⊳ P ∥ R ∼ Q ∥ R"
proof -
  obtain AR ΨR where "extractFrame R = ⟨AR, ΨR⟩" and "AR ♯* Ψ" and "AR ♯* P" and "AR ♯* Q"
    by(rule_tac C="(Ψ, P, Q)" in freshFrame) auto
  moreover from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊗ ΨR ⊳ P ∼ Q" by(rule bisimE)
  ultimately show ?thesis by(rule_tac bisimParPresAux)
qed

end

end