Theory Bisim_Pres

theory Bisim_Pres
  imports Bisimulation Sim_Pres
begin

text ‹This file is a (heavily modified) variant of the theory {\it Psi\_Calculi.Bisim\_Pres}
from~\cite{DBLP:journals/afp/Bengtson12}.›

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
  then show ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ P Q)
    then show ?case by auto
  next
    case(cSim Ψ P Q)
    then show ?case by(blast intro: inputPres)
  next
    case(cExt Ψ P Q Ψ')
    then show ?case by(blast dest: bisimE)
  next
    case(cSym Ψ P Q)
    then show ?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
  then show ?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) ∈ set CsP ⟹ ∃Q. (φ, Q) ∈ set CsQ ∧ guarded Q ∧ Ψ ⊳ P ∼ Q"
  and   "⋀φ Q. (φ, Q) ∈ set CsQ ⟹ ∃P. (φ, P) ∈ set CsP ∧ guarded P ∧ Ψ ⊳ P ∼ Q"

shows "Ψ ⊳ Cases CsP ∼ Cases CsQ"
proof -
  let ?X = "{(Ψ, Cases CsP, Cases CsQ) | Ψ CsP CsQ. (∀φ P. (φ, P) ∈ set CsP ⟶ (∃Q. (φ, Q) ∈ set CsQ ∧ guarded Q ∧ Ψ ⊳ P ∼ Q)) ∧
                                                     (∀φ Q. (φ, Q) ∈ set CsQ ⟶ (∃P. (φ, P) ∈ set CsP ∧ guarded P ∧ Ψ ⊳ P ∼ Q))}"
  from assms have "(Ψ, Cases CsP, Cases CsQ) ∈ ?X" by auto
  then show ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ P Q)
    then show ?case by auto
  next
    case(cSim Ψ CasesP CasesQ)
    then obtain CsP CsQ where C1: "⋀φ Q. (φ, Q) ∈ set CsQ ⟹ ∃P. (φ, P) ∈ set 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)
    then show ?case using A B by blast
  next
    case(cExt Ψ P Q)
    then show ?case by(blast dest: bisimE)
  next
    case(cSym Ψ P Q)
    then show ?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 = "{(Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) | Ψ xvec P Q. Ψ ⊳ P ∼ Q ∧ xvec ♯* Ψ}"
  have "eqvt ?X" using bisimClosed pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst]
    by(auto simp add: eqvts eqvt_def) blast
  have "(Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X"
  proof -
    from ‹x ♯ Ψ› have "[x] ♯* Ψ"
      by auto
    with ‹Ψ ⊳ P ∼ Q› show ?thesis
      by (smt (z3) mem_Collect_eq resChain.base resChain.step)
  qed
  then show ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ xP xQ)
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain xvec P Q where "Ψ ⊳ P ∼ Q" and "xvec ♯* Ψ" and "xP = ⦇ν*xvec⦈P" and "xQ = ⦇ν*xvec⦈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: frameResChainPres)
  next
    case(cSim Ψ xP xQ)
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain xvec P Q where "Ψ ⊳ P ∼ Q" and "xvec ♯* Ψ" and "xP = ⦇ν*xvec⦈P" and "xQ = ⦇ν*xvec⦈Q"
      by auto
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊳ P ↝[bisim] Q" by(rule bisimE)
    note ‹eqvt ?X›
    then have "eqvt(?X ∪ bisim)" by auto
    from ‹xvec ♯* Ψ›
    have "Ψ ⊳ ⦇ν*xvec⦈P ↝[(?X ∪ bisim)] ⦇ν*xvec⦈Q"
    proof(induct xvec)
      case Nil
      have "Ψ ⊳ ⦇ν*[]⦈P ↝[bisim] ⦇ν*[]⦈Q" using ‹Ψ ⊳ P ∼ Q›
        unfolding resChain.simps
        by(rule bisimE)
      then show ?case by(rule monotonic) auto
    next
      case(Cons x xvec)
      then have "x ♯ Ψ" and "xvec ♯* Ψ"
        by auto
      from ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈P ↝[(?X ∪ bisim)] ⦇ν*xvec⦈Q"
        by(rule Cons)
      moreover note ‹eqvt(?X ∪ bisim)›
      moreover note ‹x ♯ Ψ›
      moreover have "?X ∪ bisim ⊆ ?X ∪ bisim" by auto
      moreover have "⋀Ψ P Q xvec. ⟦(Ψ, P, Q) ∈ ?X ∪ bisim; xvec ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
        by (smt (verit, ccfv_threshold) Un_iff freshChainAppend mem_Collect_eq prod.inject resChainAppend)
      ultimately have "Ψ ⊳ ⦇νx⦈(⦇ν*xvec⦈P) ↝[(?X ∪ bisim)] ⦇νx⦈(⦇ν*xvec⦈Q)"
        by(rule resPres)
      then show ?case unfolding resChain.simps by -
    next
    qed
    with ‹xP = ⦇ν*xvec⦈P› ‹xQ = ⦇ν*xvec⦈Q› show ?case
      by simp
  next
    case(cExt Ψ xP xQ Ψ')
    from ‹(Ψ, xP, xQ) ∈ ?X› obtain xvec P Q where "Ψ ⊳ P ∼ Q" and "xvec ♯* Ψ" and xpe: "xP = ⦇ν*xvec⦈P" and xqe: "xQ = ⦇ν*xvec⦈Q"
      by auto
    obtain p::"name prm" where "(p∙xvec) ♯* Ψ" and "(p∙xvec) ♯* Ψ'" and "(p∙xvec) ♯* P" and "(p∙xvec) ♯* Q" and "(p∙xvec) ♯* xvec" and "distinctPerm p" and "set p ⊆ (set xvec) × (set (p∙xvec))"
      by(rule name_list_avoiding[where c="(Ψ,Ψ',P,Q,xvec)"]) auto
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊗ (p∙Ψ') ⊳ P ∼ Q"
      by(rule bisimE)
    moreover have "xvec ♯* (Ψ ⊗ (p∙Ψ'))" using ‹xvec ♯* Ψ› ‹(p∙xvec) ♯* Ψ'› ‹distinctPerm p›
      apply(intro freshCompChain)
       apply assumption
      apply(subst perm_bool[where pi=p,symmetric])
      by(simp add: eqvts)
    ultimately have "(Ψ ⊗ (p∙Ψ'),⦇ν*xvec⦈P,⦇ν*xvec⦈Q) ∈ ?X"
      by auto
    then have "(p∙(Ψ ⊗ (p∙Ψ'),⦇ν*xvec⦈P,⦇ν*xvec⦈Q)) ∈ ?X" using ‹eqvt ?X›
      by(intro eqvtI)
    then have "(Ψ ⊗ Ψ',⦇ν*(p∙xvec)⦈(p∙P),⦇ν*(p∙xvec)⦈(p∙Q)) ∈ ?X" using ‹distinctPerm p› ‹set p ⊆ (set xvec) × (set (p∙xvec))› ‹xvec ♯* Ψ› ‹(p∙xvec) ♯* Ψ›
      by(simp add: eqvts)
    then have "(Ψ ⊗ Ψ',⦇ν*xvec⦈P,⦇ν*xvec⦈Q) ∈ ?X" using ‹(p ∙ xvec) ♯* Q› ‹(p ∙ xvec) ♯* P› ‹set p ⊆ set xvec × set (p ∙ xvec)› ‹distinctPerm p›
      by(subst (1 2) resChainAlpha[where p=p]) auto
    then show ?case unfolding xpe xqe
      by blast
  next
    case(cSym Ψ P Q)
    then show ?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"

    then have "(Ψ, ⦇ν*xvec⦈(P ∥ R), ⦇ν*xvec⦈(Q ∥ R)) ∈ ?X"
      by auto 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 name_list_avoiding[where c="(Ψ, P, Q, R, ΨR, C)"]) auto
      from FrR ‹(p ∙ AR) ♯* ΨR› S have "extractFrame R = ⟨(p ∙ AR), p ∙ ΨR⟩" by(simp add: frameChainAlpha')

      moreover assume "AR ♯* Ψ"
      then have "(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"
      then have "(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"
      then have "(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
      then have "(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"
    unfolding eqvt_def
  proof
    fix x
    assume "x ∈ ?X"
    then obtain xvec Ψ P Q R where 1: "x = (Ψ, ⦇ν*xvec⦈P ∥ R, ⦇ν*xvec⦈Q ∥ R)" and 2: "xvec ♯* Ψ" and
      3: "∀AR ΨR. extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* Ψ ∧ AR ♯* P ∧ AR ♯* Q ⟶ Ψ ⊗ ΨR ⊳ P ∼ Q"
      by blast
    show "∀p::(name × name) list. p ∙ x ∈ ?X"
    proof
      fix p :: "(name × name) list"
      from 1 have "p ∙ x = (p ∙ Ψ, ⦇ν*p ∙ xvec⦈(p ∙ P) ∥ (p ∙ R), ⦇ν*p ∙ xvec⦈(p ∙ Q) ∥ (p ∙ R))"
        by (simp add: eqvts)
      moreover from 2 have "(p ∙ xvec) ♯* (p ∙ Ψ)"
        by (simp add: fresh_star_bij(2))
      moreover have "∀AR ΨR. extractFrame (p ∙ R) = ⟨AR, ΨR⟩ ∧ AR ♯* (p ∙ Ψ) ∧ AR ♯* (p ∙ P) ∧ AR ♯* (p ∙ Q) ⟶ (p ∙ Ψ) ⊗ ΨR ⊳ (p ∙ P) ∼ (p ∙ Q)"
      proof (rule allI, rule allI, rule impI, (erule conjE)+)
        fix AR ΨR
        assume exF: "extractFrame (p ∙ R) = ⟨AR, ΨR⟩" and freshPsi: "AR ♯* (p ∙ Ψ)" and freshP: "AR ♯* (p ∙ P)" and freshQ: "AR ♯* (p ∙ Q)"
        from exF have "extractFrame R = ⟨rev p ∙ AR, rev p ∙ ΨR⟩"
          by (metis Chain.simps(5) extractFrameEqvt(1) frame.perm(1) frameResChainEqvt)
        moreover from freshPsi have "(rev p ∙ AR) ♯* Ψ"
          by (metis fresh_star_bij(2) perm_pi_simp(1))
        moreover from freshP have "(rev p ∙ AR) ♯* P"
          by (metis fresh_star_bij(2) perm_pi_simp(1))
        moreover from freshQ have "(rev p ∙ AR) ♯* Q"
          by (metis fresh_star_bij(2) perm_pi_simp(1))
        ultimately show "(p ∙ Ψ) ⊗ ΨR ⊳ p ∙ P ∼ p ∙ Q"
          using 3 by (metis (no_types, opaque_lifting) bisimClosed perm_pi_simp(2) statEqvt')
      qed
      ultimately show "p ∙ x ∈ ?X"
        by blast
    qed
  qed

  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(cases "(Ψ, P, Q) ∈ ?X")
      assume "(Ψ, P, Q) ∈ ?X"
      then obtain xvec P' Q' R where "P = ⦇ν*xvec⦈P' ∥ R" and "Q = ⦇ν*xvec⦈Q' ∥ R" and "xvec ♯* Ψ"
          and "∀AR ΨR. extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* Ψ ∧ AR ♯* P' ∧ AR ♯* Q' ⟶ Ψ ⊗ ΨR ⊳ P' ∼ Q'"
        by blast
      moreover have "⦇νx⦈(⦇ν*xvec⦈P' ∥ R) = ⦇ν*(x # xvec)⦈P' ∥ R"
        by simp
      moreover have "⦇νx⦈(⦇ν*xvec⦈Q' ∥ R) = ⦇ν*(x # xvec)⦈Q' ∥ R"
        by simp
      moreover from ‹x ♯ Ψ› ‹xvec ♯* Ψ› have "(x # xvec) ♯* Ψ"
        by simp
      ultimately have "(Ψ, ⦇νx⦈P, ⦇νx⦈Q) ∈ ?X"
        by blast
      then show ?thesis by simp
    next
      assume "¬(Ψ, P, Q) ∈ ?X"
      with ‹(Ψ, P, Q) ∈ ?X ∪ bisim› have "Ψ ⊳ P ∼ Q"
        by blast
      then have "Ψ ⊳ ⦇νx⦈P ∼ ⦇νx⦈Q" using ‹x ♯ Ψ›
        by(rule bisimResPres)
      then show ?thesis
        by simp
    qed
  qed
  have ResChain: "⋀Ψ P Q xvec. ⟦(Ψ, P, Q) ∈ ?X ∪ bisim; xvec ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
  proof -
    fix Ψ P Q
      and xvec::"name list"
    assume "(Ψ, P, Q) ∈ ?X ∪ bisim"
      and "xvec ♯* Ψ"
    then show "(Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
    proof(induct xvec)
      case Nil then show ?case by simp
    next
      case(Cons x xvec)
      then have "(Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
        by simp
      moreover have "x ♯ Ψ" using Cons by simp
      ultimately show ?case unfolding resChain.simps
        by(rule Res)
    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 name_list_avoiding[where c="(AR, Ψ, ΨR', P, Q)"]) 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
      then have "(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)
      then have "(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)
    }
    then show ?thesis
      apply clarsimp
      apply(rule exI[where x="[]"])
      by auto blast
  qed
  then show ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ PR QR)
    from ‹(Ψ, PR, QR) ∈ ?X›
    obtain xvec P Q R where PFrR: "PR = ⦇ν*xvec⦈(P ∥ R)" and QFrR: "QR = ⦇ν*xvec⦈(Q ∥ R)"
      and "xvec ♯* Ψ" and *: "∀AR ΨR. extractFrame R = ⟨AR, ΨR⟩ ∧ AR ♯* Ψ ∧ AR ♯* P ∧ AR ♯* Q ⟶ Ψ ⊗ ΨR ⊳ P ∼ Q"
      by blast
    obtain AR ΨR where FrR: "extractFrame R = ⟨AR, ΨR⟩" and fresh: "AR ♯* (Ψ, P, Q, R)"
      using freshFrame by metis
    from fresh have "AR ♯* Ψ" and "AR ♯* P" and "AR ♯* Q" and "AR ♯* R"
      by auto
    with FrR have PSimQ: "Ψ ⊗ ΨR ⊳ P ∼ Q"
      using * by blast

    obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "AP ♯* AR" and "AP ♯* ΨR"
      by(rule freshFrame[where C="(Ψ, AR, ΨR)"]) auto
    obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* AR" and "AQ ♯* ΨR"
      by(rule freshFrame[where C="(Ψ, AR, ΨR)"]) 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)
      then have "⟨(AR@AP), Ψ ⊗ ΨP ⊗ ΨR⟩ ≃F ⟨(AR@AQ), Ψ ⊗ ΨQ ⊗ ΨR⟩"
        by(drule_tac frameResChainPres) (simp add: frameChainAppend)
      then show ?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"
        then have "(Ψ, 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 name_list_avoiding[where c="(AR, Ψ, ΨR', P, Q)"]) 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 clarsimp
              apply(drule sym)
              apply simp
              by(drule 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)
            then have "(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
        then have "(Ψ, 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) ♯* Ψ"
        then show "(Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X ∪ bisim"
        proof(induct xvec)
          case Nil
          then show ?case using ‹(Ψ, P, Q) ∈ ?X ∪ bisim› by simp
        next
          case(Cons x xvec)
          then show ?case by(simp only: resChain.simps) (rule 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 ResChain
        by(intro 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 name_list_avoiding[where c="(Ψ, P, Q, R, Ψ')"]) auto

    from ‹(p ∙ xvec) ♯* P› ‹(p ∙ xvec) ♯* R› S have "⦇ν*xvec⦈(P ∥ R) = ⦇ν*(p ∙ xvec)⦈(p ∙ (P ∥ R))"
      by(subst resChainAlpha) auto
    then have 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
    then have QRAlpha: "⦇ν*xvec⦈(Q ∥ R) = ⦇ν*(p ∙ xvec)⦈((p ∙ Q) ∥ (p ∙ R))"
      by(simp add: eqvts)

    have "(Ψ ⊗ Ψ', ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ (p ∙ R)), ⦇ν*(p ∙ xvec)⦈((p ∙ Q) ∥ (p ∙ R))) ∈ ?X"
    proof(rule XI'[where C2="(Ψ, (p ∙ P), (p ∙ Q), R, Ψ', xvec, p ∙ xvec)"])
      show "(p ∙ xvec) ♯* (Ψ ⊗ Ψ')"
        using ‹(p ∙ xvec) ♯* Ψ› ‹(p ∙ xvec) ♯* Ψ'› by auto
    next
      fix AR ΨR
      assume FrR: "extractFrame (p ∙ R) = ⟨AR, ΨR⟩" and "AR ♯* (Ψ ⊗ Ψ')" and "AR ♯* (p ∙ P)" and "AR ♯* (Ψ, p ∙ P, p ∙ Q, R, Ψ', xvec, p ∙ xvec)"
      then have "AR ♯* Ψ" and "AR ♯* (p ∙ Q)"
        by simp_all
      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
      then have "(Ψ ⊗ (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)
      then have "(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)
    then show ?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 freshFrame[where C="(Ψ, P, Q)"]) auto
  moreover from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊗ ΨR ⊳ P ∼ Q" by(rule bisimE)
  ultimately show ?thesis by(intro bisimParPresAux)
qed

end

end