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 "Ψ  MN⟩.P  MN⟩.Q"
proof -
  let ?X = "{(Ψ, MN⟩.P, MN⟩.Q) | Ψ M N P Q. Ψ  P  Q}"
  from Ψ  P  Q have "(Ψ, MN⟩.P, MN⟩.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 "Ψ  ⦇νxP  ⦇νxQ"
proof -
  let ?X = "{(Ψ, ⦇ν*xvecP, ⦇ν*xvecQ) | Ψ 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 "(Ψ, ⦇νxP, ⦇νxQ)  ?X"
  proof -
    from x  Ψ have "[x] ♯* Ψ"
      by auto
    with Ψ  P  Q show ?thesis
      by (smt 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 = ⦇ν*xvecP" and "xQ = ⦇ν*xvecQ"
      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 = ⦇ν*xvecP" and "xQ = ⦇ν*xvecQ"
      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 "Ψ  ⦇ν*xvecP ↝[(?X  bisim)] ⦇ν*xvecQ"
    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 "Ψ  ⦇ν*xvecP ↝[(?X  bisim)] ⦇ν*xvecQ"
        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 ♯* Ψ  (Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?X  bisim"
        by (smt (verit, ccfv_threshold) Un_iff freshChainAppend mem_Collect_eq prod.inject resChainAppend)
      ultimately have "Ψ  ⦇νx(⦇ν*xvecP) ↝[(?X  bisim)] ⦇νx(⦇ν*xvecQ)"
        by(rule resPres)
      then show ?case unfolding resChain.simps by -
    next
    qed
    with xP = ⦇ν*xvecP xQ = ⦇ν*xvecQ 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 = ⦇ν*xvecP" and xqe: "xQ = ⦇ν*xvecQ"
      by auto
    obtain p::"name prm" where "(pxvec) ♯* Ψ" and "(pxvec) ♯* Ψ'" and "(pxvec) ♯* P" and "(pxvec) ♯* Q" and "(pxvec) ♯* xvec" and "distinctPerm p" and "set p  (set xvec) × (set (pxvec))"
      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 ♯* Ψ (pxvec) ♯* Ψ' distinctPerm p
      apply(intro freshCompChain)
       apply assumption
      apply(subst perm_bool[where pi=p,symmetric])
      by(simp add: eqvts)
    ultimately have "(Ψ  (pΨ'),⦇ν*xvecP,⦇ν*xvecQ)  ?X"
      by auto
    then have "(p(Ψ  (pΨ'),⦇ν*xvecP,⦇ν*xvecQ))  ?X" using eqvt ?X
      by(intro eqvtI)
    then have "(Ψ  Ψ',⦇ν*(pxvec)(pP),⦇ν*(pxvec)(pQ))  ?X" using distinctPerm p set p  (set xvec) × (set (pxvec)) xvec ♯* Ψ (pxvec) ♯* Ψ
      by(simp add: eqvts)
    then have "(Ψ  Ψ',⦇ν*xvecP,⦇ν*xvecQ)  ?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 "Ψ  ⦇ν*xvecP  ⦇ν*xvecQ"
  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 = (Ψ, ⦇ν*xvecP  R, ⦇ν*xvecQ  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  Ψ  (Ψ, ⦇νxP, ⦇νxQ)  ?X  bisim"
  proof -
    fix Ψ P Q x
    assume "(Ψ, P, Q)  ?X  bisim" and "(x::name)  Ψ"
    show "(Ψ, ⦇νxP, ⦇νxQ)  ?X  bisim"
    proof(cases "(Ψ, P, Q)  ?X")
      assume "(Ψ, P, Q)  ?X"
      then obtain xvec P' Q' R where "P = ⦇ν*xvecP'  R" and "Q = ⦇ν*xvecQ'  R" and "xvec ♯* Ψ"
          and "AR ΨR. extractFrame R = AR, ΨR  AR ♯* Ψ  AR ♯* P'  AR ♯* Q'  Ψ  ΨR  P'  Q'"
        by blast
      moreover have "⦇νx(⦇ν*xvecP'  R) = ⦇ν*(x # xvec)P'  R"
        by simp
      moreover have "⦇νx(⦇ν*xvecQ'  R) = ⦇ν*(x # xvec)Q'  R"
        by simp
      moreover from x  Ψ xvec ♯* Ψ have "(x # xvec) ♯* Ψ"
        by simp
      ultimately have "(Ψ, ⦇νxP, ⦇νxQ)  ?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 "Ψ  ⦇νxP  ⦇νxQ" using x  Ψ
        by(rule bisimResPres)
      then show ?thesis
        by simp
    qed
  qed
  have ResChain: "Ψ P Q xvec. (Ψ, P, Q)  ?X  bisim; xvec ♯* Ψ  (Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?X  bisim"
  proof -
    fix Ψ P Q
      and xvec::"name list"
    assume "(Ψ, P, Q)  ?X  bisim"
      and "xvec ♯* Ψ"
    then show "(Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?X  bisim"
    proof(induct xvec)
      case Nil then show ?case by simp
    next
      case(Cons x xvec)
      then have "(Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?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(⦇ν*xvecP  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(⦇ν*xvecQ  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) ♯* Ψ  (Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?X  bisim"
      proof -
        fix Ψ P Q xvec
        assume "(Ψ, P, Q)  ?X  bisim"
        assume "(xvec::name list) ♯* Ψ"
        then show "(Ψ, ⦇ν*xvecP, ⦇ν*xvecQ)  ?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