Theory Bisim_Struct_Cong

theory Bisim_Struct_Cong
  imports Bisim_Pres Sim_Struct_Cong "Psi_Calculi.Structural_Congruence"
begin

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

context env begin

lemma bisimParComm:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"

shows "Ψ ⊳ P ∥ Q ∼ Q ∥ P"
proof -
  let ?X = "{((Ψ::'b), ⦇ν*xvec⦈((P::('a, 'b, 'c) psi) ∥ Q), ⦇ν*xvec⦈(Q ∥ P)) | xvec Ψ P Q. xvec ♯* Ψ}"

  have "eqvt ?X"
    by(force simp add: eqvt_def pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst] eqvts)

  have "(Ψ, P ∥ Q, Q ∥ P) ∈ ?X"
    using resChain.base by(smt (verit) freshSets(1) mem_Collect_eq)
  then show ?thesis
  proof(coinduct rule: bisimWeakCoinduct)
    case(cStatEq Ψ PQ QP)
    from ‹(Ψ, PQ, QP) ∈ ?X›
    obtain xvec P Q where PFrQ: "PQ = ⦇ν*xvec⦈(P ∥ Q)" and QFrP: "QP = ⦇ν*xvec⦈(Q ∥ P)" and "xvec ♯* Ψ"
      by auto

    obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "AP ♯* Q"
      by(rule freshFrame[where C="(Ψ, Q)"]) auto
    obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* AP" and "AQ ♯* ΨP"
      by(rule freshFrame[where C="(Ψ, AP, ΨP)"]) auto
    from FrQ ‹AQ ♯* AP› ‹AP ♯* Q› have "AP ♯* ΨQ" by(force dest: extractFrameFreshChain)
    have "⟨(xvec@AP@AQ), Ψ ⊗ ΨP ⊗ ΨQ⟩ ≃F ⟨(xvec@AQ@AP), Ψ ⊗ ΨQ ⊗ ΨP⟩"
      by(simp add: frameChainAppend)
        (metis frameResChainPres frameResChainComm frameNilStatEq compositionSym Associativity Commutativity FrameStatEqTrans)
    with FrP FrQ PFrQ QFrP ‹AP ♯* ΨQ› ‹AQ ♯* ΨP› ‹AQ ♯* AP› ‹xvec ♯* Ψ› ‹AP ♯* Ψ› ‹AQ ♯* Ψ›
    show ?case by(auto simp add: frameChainAppend)
  next
    case(cSim Ψ PQ QP)
    from ‹(Ψ, PQ, QP) ∈ ?X›
    obtain xvec P Q where PFrQ: "PQ = ⦇ν*xvec⦈(P ∥ Q)" and QFrP: "QP = ⦇ν*xvec⦈(Q ∥ P)"
      and "xvec ♯* Ψ"
      by auto
    moreover have "Ψ ⊳ ⦇ν*xvec⦈(P ∥ Q) ↝[?X] ⦇ν*xvec⦈(Q ∥ P)"
    proof -
      have "Ψ ⊳ P ∥ Q ↝[?X] Q ∥ P"
      proof -
        note ‹eqvt ?X›
        moreover have "⋀Ψ P Q. (Ψ, P ∥ Q, Q ∥ P) ∈ ?X"
          using resChain.base by(smt (verit) freshSets(1) mem_Collect_eq)
        moreover have "⋀Ψ P Q xvec. ⟦(Ψ, P, Q) ∈ ?X; xvec ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X"
        proof (induct xvec)
          case Nil
          then show ?case
            by (smt (verit, ccfv_threshold) Pair_inject freshChainAppend mem_Collect_eq resChainAppend)
        next
          case (Cons a xvec)
          then show ?case
            by blast
        qed
        ultimately show ?thesis by(rule simParComm)
      qed
      moreover note ‹eqvt ?X› ‹xvec ♯* Ψ›
      moreover have "⋀Ψ P Q xvec. ⟦(Ψ, P, Q) ∈ ?X; xvec ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*xvec⦈P, ⦇ν*xvec⦈Q) ∈ ?X"
        using resChainAppend[symmetric] freshChainAppend by blast
      ultimately show ?thesis
        by(rule resChainPres)
    qed
    ultimately show ?case by simp
  next
    case(cExt Ψ PQ QP Ψ')
    from ‹(Ψ, PQ, QP) ∈ ?X›
    obtain xvec P Q where PFrQ: "PQ = ⦇ν*xvec⦈(P ∥ Q)" and QFrP: "QP = ⦇ν*xvec⦈(Q ∥ P)"
      and "xvec ♯* Ψ"
      by auto

    obtain p where "(p ∙ xvec) ♯* Ψ"
      and "(p ∙ xvec) ♯* P"
      and "(p ∙ xvec) ♯* Q"
      and "(p ∙ xvec) ♯* Ψ'"
      and S: "(set p) ⊆ (set xvec) × (set(p ∙ xvec))" and "distinctPerm p"
      by(rule name_list_avoiding[where c="(Ψ, P, Q, Ψ')"]) auto

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

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

    from ‹(p ∙ xvec) ♯* Ψ› ‹(p ∙ xvec) ♯* Ψ'› have "(Ψ ⊗ Ψ', ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ (p ∙ Q)), ⦇ν*(p ∙ xvec)⦈((p ∙ Q) ∥ (p ∙ P))) ∈ ?X"
      by auto
    with PFrQ QFrP PQAlpha QPAlpha show ?case by simp
  next
    case(cSym Ψ PR QR)
    then show ?case by blast
  qed
qed

inductive_set resCommRel :: "('b × ('a,'b,'c) psi × ('a,'b,'c) psi) set"
  where
    resCommRel_refl : "(Ψ,P,P) ∈ resCommRel"
  | resCommRel_swap : "⟦a ♯ Ψ; b ♯ Ψ⟧ ⟹ (Ψ,⦇νa⦈(⦇νb⦈P),⦇νb⦈(⦇νa⦈P)) ∈ resCommRel"
  | resCommRel_res : "⟦(Ψ,P,Q) ∈ resCommRel; a ♯ Ψ⟧ ⟹ (Ψ,⦇νa⦈P,⦇νa⦈Q) ∈ resCommRel"

lemma eqvtResCommRel: "eqvt resCommRel"
proof -
  {
    fix Ψ P Q
      and p::"name prm"
    assume "(Ψ,P,Q) ∈ resCommRel"
    then have "(p∙Ψ,p∙P,p∙Q) ∈ resCommRel"
    proof(induct rule: resCommRel.inducts)
      case resCommRel_refl then show ?case by(rule resCommRel.intros)
    next
      case(resCommRel_swap a Ψ b P)
      then have "(p∙a) ♯ p∙Ψ" and "(p∙b) ♯ p∙Ψ"
         apply -
        by(subst (asm) (1 2) perm_bool[where pi=p,symmetric], simp add: eqvts)+
      then show ?case unfolding eqvts
        by(rule resCommRel.intros)
    next
      case(resCommRel_res Ψ P Q a)
      from ‹a ♯ Ψ› have "(p∙a) ♯ p∙Ψ"
        apply -
        by(subst (asm) perm_bool[where pi=p,symmetric], simp add: eqvts)
      then show ?case using ‹(p ∙ Ψ, p ∙ P, p ∙ Q) ∈ resCommRel›
        unfolding eqvts
        by(intro resCommRel.intros)
    qed
  }
  then show ?thesis unfolding eqvt_def
    by auto
qed

lemma resCommRelStarRes:
  assumes "(Ψ,P,Q) ∈ resCommRel⋆"
    and   "a ♯ Ψ"
  shows   "(Ψ,⦇νa⦈P,⦇νa⦈Q) ∈ resCommRel⋆"
  using assms
proof(induct rule: rel_trancl.induct)
  case r_into_rel_trancl then show ?case by(auto intro: resCommRel_res)
next
  case(rel_trancl_into_rel_trancl Ψ P Q R)
  then show ?case
    by(auto dest: resCommRel_res intro: rel_trancl.intros)
qed

lemma resCommRelStarResChain:
  assumes "(Ψ,P,Q) ∈ resCommRel⋆"
    and   "xvec ♯* Ψ"
  shows   "(Ψ,⦇ν*xvec⦈P,⦇ν*xvec⦈Q) ∈ resCommRel⋆"
  using assms
  by(induct xvec) (auto simp add: resCommRelStarRes)

lemma length_induct1[consumes 0, case_names Nil Cons]:
  assumes b: "P []"
    and   s: "⋀ x xvec. ⟦⋀ yvec. length xvec=length yvec⟹P yvec⟧ ⟹ P(x#xvec)"
  shows   "P xvec"
proof(induct xvec rule: length_induct)
  case(1 xvec)
  then show ?case
  proof(cases xvec)
    case Nil then show ?thesis by(simp add: b)
  next
    case(Cons y yvec)
    with ‹∀ys. length ys < length xvec ⟶ P ys› have "∀ys. length ys = length yvec ⟶ P ys" by simp
    then show ?thesis unfolding Cons
      using s by auto
  qed
qed

lemma oneStepPerm_in_rel:
  assumes "xvec ♯* Ψ"
  shows "(Ψ,⦇ν*xvec⦈P,⦇ν*(rotate1 xvec)⦈P) ∈ resCommRel⋆"
  using assms
proof(induct xvec rule: length_induct1)
  case Nil then show ?case by(auto intro: resCommRel_refl)
next
  case(Cons x xvec)
  note Cons1 = this
  show ?case
  proof(cases xvec)
    case Nil then show ?thesis
      by(auto intro: resCommRel_refl)
  next
    case(Cons y yvec)
    then have "x ♯ Ψ" and "y ♯ Ψ" and "xvec ♯* Ψ" using ‹(x # xvec) ♯* Ψ›
      by simp+
    have "(Ψ, ⦇ν*(x#y#yvec)⦈P, ⦇ν*(y#x#yvec)⦈P) ∈ resCommRel⋆" using ‹x ♯ Ψ› ‹y ♯ Ψ›
      by(auto intro: resCommRel_swap)
    moreover have "(Ψ, ⦇ν*(y#x#yvec)⦈P, ⦇ν*(y#rotate1(x#yvec))⦈P) ∈ resCommRel⋆"
    proof -
      have "(Ψ, ⦇ν*(x#yvec)⦈P, ⦇ν*rotate1(x#yvec)⦈P) ∈ resCommRel⋆" using ‹xvec ♯* Ψ› Cons ‹x ♯ Ψ›
        by(intro Cons1) auto
      then show ?thesis using ‹y ♯ Ψ›
        unfolding resChain.simps
        by(rule resCommRelStarRes)
    qed
    ultimately show ?thesis unfolding Cons
      by(auto intro: rel_trancl_transitive)
  qed
qed

lemma fresh_same_multiset:
  fixes xvec::"name list"
    and yvec::"name list"
  assumes "mset xvec = mset yvec"
    and   "xvec ♯* X"
  shows   "yvec ♯* X"
proof -
  from ‹mset xvec = mset yvec› have "set xvec = set yvec"
    using mset_eq_setD by blast
  then show ?thesis using ‹xvec ♯* X›
    unfolding fresh_def fresh_star_def name_list_supp
    by auto
qed

lemma nStepPerm_in_rel:
  assumes "xvec ♯* Ψ"
  shows "(Ψ,⦇ν*xvec⦈P,⦇ν*(rotate n xvec)⦈P) ∈ resCommRel⋆"
  using assms
proof(induct n)
  case 0 then show ?case by(auto intro: resCommRel_refl)
next
  case(Suc n)
  then have "(Ψ, ⦇ν*xvec⦈P, ⦇ν*rotate n xvec⦈P) ∈ resCommRel⋆"
    by simp
  moreover have "(Ψ, ⦇ν*rotate n xvec⦈P,⦇ν*rotate (Suc n) xvec⦈P) ∈ resCommRel⋆"
  proof -
    {
      fix xvec::"name list"
      assume "xvec ♯* Ψ"
      have "rotate1 xvec ♯* Ψ" using ‹xvec ♯* Ψ›
      proof(induct xvec)
        case Nil then show ?case by simp
      next
        case Cons then show ?case by simp
      qed
    }
    note f1 = this
    have "rotate n xvec ♯* Ψ" using ‹xvec ♯* Ψ›
      by(induct n) (auto simp add: f1)
    then show ?thesis
      by(auto simp add: oneStepPerm_in_rel)
  qed
  ultimately show ?case
    by(rule rel_trancl_transitive)
qed

lemma any_perm_in_rel:
  assumes "xvec ♯* Ψ"
    and   "mset xvec = mset yvec"
  shows "(Ψ,⦇ν*xvec⦈P,⦇ν*yvec⦈P) ∈ resCommRel⋆"
  using assms
proof(induct xvec arbitrary: yvec rule: length_induct1)
  case Nil then show ?case by(auto intro: resCommRel.intros)
next
  case(Cons x xvec)
  obtain yvec1 yvec2 where yveceq: "yvec=yvec1@x#yvec2"
  proof -
    assume 1: "⋀yvec1 yvec2. yvec = yvec1 @ x # yvec2 ⟹ thesis"
    {
      note ‹mset (x # xvec) = mset yvec›
      then have "∃ yvec1 yvec2. yvec=yvec1@x#yvec2"
      proof(induct xvec arbitrary: yvec rule: length_induct1)
        case Nil
        from ‹mset [x] = mset yvec› have "yvec = [x]"
          apply(induct yvec)
           apply simp
          apply(simp add: single_is_union)
          done
        then show ?case by blast
      next
        case(Cons x' xvec)
        have less: "{#x'#} ⊆# mset yvec" unfolding ‹mset (x # x' # xvec) = mset yvec›[symmetric]
          by simp
        from ‹mset (x # x' # xvec) = mset yvec›
        have "mset (x # xvec) = mset (remove1 x' yvec)"
          by (metis mset_remove1 remove1.simps(2))
        then have "∃yvec1 yvec2. (remove1 x' yvec) = yvec1 @ x # yvec2"
          by(intro Cons) simp+
        then obtain yvec1 yvec2 where "(remove1 x' yvec) = yvec1 @ x # yvec2"
          by blast
        then show ?case
        proof(induct yvec arbitrary: yvec1 yvec2)
          case Nil then show ?case by simp
        next
          case(Cons y yvec) then show ?case
          proof(cases "x'=y")
            case True
            with ‹remove1 x' (y # yvec) = yvec1 @ x # yvec2›
            have "yvec = yvec1 @ x # yvec2"
              by simp
            then show ?thesis
              by (metis append_Cons)
          next
            case False
            then have "remove1 x' (y#yvec) = y # remove1 x' (yvec)"
              by simp
            note Cons2=Cons
            show ?thesis
            proof(cases yvec1)
              case Nil
              then show ?thesis using Cons2 False
                by auto
            next
              case(Cons y1 yvec1a)
              from ‹remove1 x' (y # yvec) = yvec1 @ x # yvec2› ‹yvec1 = y1 # yvec1a› False have "y1=y"
                by simp
              from ‹remove1 x' (y # yvec) = yvec1 @ x # yvec2›
              have "remove1 x' yvec = yvec1a @ x # yvec2" unfolding Cons ‹y1=y› using False
                by simp
              then have "∃yvec1 yvec2. yvec = yvec1 @ x # yvec2"
                by(rule Cons2)
              then obtain yvec1 yvec2 where "yvec = yvec1 @ x # yvec2"
                by blast
              then show ?thesis
                by (metis append_Cons)
            qed
          qed
        qed
      qed
    }
    then show ?thesis using 1
      by blast
  qed
  from ‹(x # xvec) ♯* Ψ› have "x ♯ Ψ" and "xvec ♯* Ψ" by auto
  have "mset (x # xvec) = mset(yvec1 @ x # yvec2)"
    unfolding yveceq[symmetric] by fact
  then have "mset (xvec) = mset(yvec1 @ yvec2)"
    by(subst add_right_cancel[symmetric,where a="{#x#}"]) (simp add: add.assoc)
  then have "(Ψ, ⦇ν*xvec⦈P, ⦇ν*(yvec1@yvec2)⦈P) ∈ resCommRel⋆" using ‹xvec ♯* Ψ›
    by(intro Cons) auto
  moreover have "(Ψ, ⦇ν*(yvec1@yvec2)⦈P, ⦇ν*(yvec2@yvec1)⦈P) ∈ resCommRel⋆"
  proof -
    have e: "yvec2 @ yvec1 = rotate (length yvec1) (yvec1@yvec2)"
      apply(cases yvec2)
       apply simp
      apply(simp add: rotate_drop_take)
      done
    have "(yvec1@yvec2) ♯* Ψ" using ‹mset (xvec) = mset(yvec1 @ yvec2)› ‹xvec ♯* Ψ›
      by(rule fresh_same_multiset)
    then show ?thesis unfolding e
      by(rule nStepPerm_in_rel)
  qed
  ultimately have "(Ψ, ⦇ν*xvec⦈P, ⦇ν*(yvec2 @ yvec1)⦈P) ∈ resCommRel⋆"
    by(rule rel_trancl_transitive)
  then have "(Ψ, ⦇ν*(x#xvec)⦈P, ⦇ν*(x # yvec2 @ yvec1)⦈P) ∈ resCommRel⋆"
    unfolding resChain.simps using ‹x ♯ Ψ›
    by(rule resCommRelStarRes)
  moreover have "(Ψ, ⦇ν*(x # yvec2 @ yvec1)⦈P, ⦇ν*(yvec1 @ x # yvec2)⦈P) ∈ resCommRel⋆"
  proof -
    have e: "yvec1 @ x # yvec2 = rotate (1+length yvec2) (x#yvec2@yvec1)"
      apply(simp add: rotate_drop_take)
      apply(cases yvec1)
      by simp+
    have "(yvec1 @ x # yvec2) ♯* Ψ" using ‹mset (x # xvec) = mset(yvec1 @ x # yvec2)› ‹(x#xvec) ♯* Ψ›
      by(rule fresh_same_multiset)
    then have "(x # yvec2 @ yvec1) ♯* Ψ" by simp
    then show ?thesis unfolding e
      by(rule nStepPerm_in_rel)
  qed
  ultimately show ?case unfolding yveceq
    by(rule rel_trancl_transitive)
qed

lemma bisimResComm:
  fixes x :: name
    and Ψ :: 'b
    and y :: name
    and P :: "('a, 'b, 'c) psi"

shows "Ψ ⊳ ⦇νx⦈(⦇νy⦈P) ∼ ⦇νy⦈(⦇νx⦈P)"
proof(cases "x=y")
  case True
  then show ?thesis by(blast intro: bisimReflexive)
next
  case False
  {
    fix x::name and y::name and P::"('a, 'b, 'c) psi"
    assume "x ♯ Ψ" and "y ♯ Ψ"
    let ?X = resCommRel
    from ‹x ♯ Ψ› ‹y ♯ Ψ› have "(Ψ, ⦇νx⦈(⦇νy⦈P), ⦇νy⦈(⦇νx⦈P)) ∈ ?X"
      by(rule resCommRel_swap)
    then have "Ψ ⊳ ⦇νx⦈(⦇νy⦈P) ∼ ⦇νy⦈(⦇νx⦈P)" using eqvtResCommRel
    proof(coinduct rule: bisimStarWeakCoinduct)
      case(cStatEq Ψ R S)
      then show ?case
      proof(induct rule: resCommRel.induct)
        case resCommRel_refl then show ?case by(rule FrameStatEqRefl)
      next
        case(resCommRel_swap x Ψ y P)
        moreover obtain AP ΨP where "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "x ♯ AP" and "y ♯ AP"
          by(rule freshFrame[where C="(x, y, Ψ)"]) auto
        ultimately show ?case by(force intro: frameResComm FrameStatEqTrans)
      next
        case(resCommRel_res Ψ P Q a)
        then show ?case by(auto intro: frameResPres)
      qed
    next
      case(cSim Ψ R S)
      have "eqvt(resCommRel⋆)"
        by(rule rel_trancl_eqvt) (rule eqvtResCommRel)
      from cSim show ?case
      proof(induct rule: resCommRel.induct)
        case(resCommRel_refl Ψ P)
        then show ?case
          by(rule simI[OF ‹eqvt(resCommRel⋆)›]) (blast intro: resCommRel.intros)
      next
        case(resCommRel_swap a Ψ b P)
        show ?case
          by(rule resComm) (fact|auto intro: resCommRel.intros any_perm_in_rel)+
      next
        case(resCommRel_res Ψ P Q a)
        show ?case
          by(rule resPres[where Rel="resCommRel⋆"]) (fact|simp add: resCommRelStarResChain)+
      qed
    next
      case(cExt Ψ R S Ψ') then show ?case
      proof(induct arbitrary: Ψ' rule: resCommRel.induct)
        case resCommRel_refl then show ?case by(rule resCommRel_refl)
      next
        case(resCommRel_swap a Ψ b P)
        then show ?case
        proof(cases "a=b")
          case True show ?thesis unfolding ‹a=b› by(rule resCommRel_refl)
        next
          case False
          obtain x::name and y::name where "x≠y" and "x ♯ Ψ" and "x ♯ Ψ'" and "x ♯ P" and "x ≠ a" and "x≠b" and "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ P" and "y ≠ a" and "y≠b"
            apply(generate_fresh "name")
            apply(generate_fresh "name")
            by force
          then show ?thesis using False
            apply(subst (1 2) alphaRes[where x=a and y=x])
              apply assumption
             apply(simp add: fresh_abs_fun_iff[OF pt_name_inst, OF at_name_inst, OF fin_supp])
            apply(subst (1 2) alphaRes[where x=b and y=y])
              apply(simp add: fresh_abs_fun_iff[OF pt_name_inst, OF at_name_inst, OF fin_supp] fresh_left)
             apply assumption
            unfolding eqvts
            apply(subst (1) cp1[OF cp_pt_inst, OF pt_name_inst, OF at_name_inst])
            by(auto simp add: eqvts swap_simps intro: resCommRel.intros)
        qed
      next
        case(resCommRel_res Ψ P Q a)
        obtain b::name where "b ♯ Ψ" and "b ≠ a" and "b ♯ P" and "b ♯ Q" and "b ♯ Ψ'"
          by(generate_fresh "name") auto
        have "(Ψ ⊗ ([(a,b)]∙Ψ'), P, Q) ∈ resCommRel" by fact
        moreover from ‹b ♯ Ψ'› have "a ♯ ([(a, b)] ∙ Ψ')" by(simp add: fresh_left swap_simps)
        with ‹a ♯ Ψ› have "a ♯ Ψ ⊗ ([(a,b)]∙Ψ')" by force
        ultimately have "(Ψ ⊗ ([(a,b)]∙Ψ'), ⦇νa⦈P, ⦇νa⦈Q) ∈ resCommRel"
          by(rule resCommRel.intros)
        then have "([(a,b)]∙(Ψ ⊗ ([(a,b)]∙Ψ'), ⦇νa⦈P, ⦇νa⦈Q)) ∈ resCommRel" using eqvtResCommRel
          by(intro eqvtI)
        then have "(Ψ ⊗ Ψ', ⦇νb⦈([(a,b)]∙P), ⦇νb⦈([(a,b)]∙Q)) ∈ resCommRel" using ‹a ♯ Ψ› ‹b ♯ Ψ›
          by(simp add: eqvts swap_simps)
        then show ?case using ‹b ♯ Q› ‹b ♯ P›
          apply(subst (1 2) alphaRes[where x=a and y=b])
          by(assumption|simp only: eqvts)+
      qed
    next
      case(cSym Ψ R S) then show ?case
        by(induct rule: resCommRel.inducts) (auto intro: resCommRel.intros)
    qed
  }
  moreover obtain x'::name where "x' ♯ Ψ" and "x' ♯ P" and "x' ≠ x" and "x' ≠ y"
    by(generate_fresh "name") auto
  moreover obtain y'::name where "y' ♯ Ψ" and "y' ♯ P" and "y' ≠ x" and "y' ≠ y" and "y' ≠ x'"
    by(generate_fresh "name") auto
  ultimately have "Ψ ⊳ ⦇νx'⦈(⦇νy'⦈([(y, y'), (x, x')] ∙ P)) ∼ ⦇νy'⦈(⦇νx'⦈([(y, y'), (x, x')] ∙ P))" by auto
  then show ?thesis using ‹x' ♯ P› ‹x' ≠ x› ‹x' ≠ y› ‹y' ♯ P› ‹y' ≠ x› ‹y' ≠ y› ‹y' ≠ x'› ‹x ≠ y›
    apply(subst alphaRes[where x=x and y=x' and P=P], auto)
    apply(subst alphaRes[where x=y and y=y' and P=P], auto)
    apply(subst alphaRes[where x=x and y=x' and P="⦇νy'⦈([(y, y')] ∙ P)"], auto simp add: abs_fresh fresh_left)
    apply(subst alphaRes[where x=y and y=y' and P="⦇νx'⦈([(x, x')] ∙ P)"], auto simp add: abs_fresh fresh_left)
    by(subst perm_compose) (simp add: eqvts calc_atm)
qed

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

assumes "x ♯ Ψ"
  and   "xvec ♯* Ψ"

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

lemma bisimParPresSym:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"
    and R :: "('a, 'b, 'c) psi"

assumes "Ψ ⊳ P ∼ Q"

shows "Ψ ⊳ R ∥ P ∼ R ∥ Q"
  using assms
  by(metis bisimParComm bisimParPres bisimTransitive)

lemma bisimScopeExt:
  fixes x :: name
    and Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"

assumes "x ♯ P"

shows "Ψ ⊳ ⦇νx⦈(P ∥ Q) ∼ P ∥ ⦇νx⦈Q"
proof -
  {
    fix x::name and Q :: "('a, 'b, 'c) psi"
    assume "x ♯ Ψ" and "x ♯ P"
    let ?X1 = "{((Ψ::'b), ⦇ν*xvec⦈(⦇ν*yvec⦈((P::('a, 'b, 'c) psi) ∥ Q)), ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))) | Ψ xvec yvec P Q. yvec ♯* Ψ ∧ yvec ♯* P ∧ xvec ♯* Ψ}"
    let ?X2 = "{((Ψ::'b), ⦇ν*xvec⦈((P::('a, 'b, 'c) psi) ∥ (⦇ν*yvec⦈Q)), ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))) | Ψ xvec yvec P Q. yvec ♯* Ψ ∧ yvec ♯* P ∧ xvec ♯* Ψ}"
    let ?X = "?X1 ∪ ?X2"
    from ‹x ♯ Ψ› ‹x ♯ P› have "(Ψ, ⦇νx⦈(P ∥ Q), P ∥ ⦇νx⦈Q) ∈ ?X"
    proof -
      from ‹x ♯ Ψ› ‹x ♯ P› have "(Ψ, ⦇νx⦈(P ∥ Q), P ∥ ⦇νx⦈Q) ∈ ?X1"
        by (smt (verit, del_insts) mem_Collect_eq freshSets(1) freshSets(5) resChain.base resChain.step)
      then show ?thesis by auto
    qed
    moreover have "eqvt ?X"
      by (rule eqvtUnion) (clarsimp simp add: eqvt_def eqvts, metis fresh_star_bij(2))+
    ultimately have "Ψ ⊳ ⦇νx⦈(P ∥ Q) ∼ P ∥ ⦇νx⦈Q"
    proof(coinduct rule: transitiveStarCoinduct)
      case(cStatEq Ψ R T)
      then have "(Ψ, R, T) ∈ ?X1 ∨ (Ψ, R, T) ∈ ?X2"
        by blast
      then show ?case
      proof(rule disjE)
        assume "(Ψ, R, T) ∈ ?X1"
        then obtain xvec yvec P Q where "R = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and "T = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        moreover obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "yvec ♯* AP" and "AP ♯* Q"
          by(rule freshFrame[where C="(Ψ, yvec, Q)"]) auto
        moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "yvec ♯* AQ" and "AQ ♯* AP" and "AQ ♯* ΨP"
          by(rule freshFrame[where C="(Ψ, yvec, AP, ΨP)"]) auto
        moreover from FrQ ‹AP ♯* Q› ‹AQ ♯* AP› have "AP ♯* ΨQ"
          by(auto dest: extractFrameFreshChain)
        moreover from ‹yvec ♯* P› ‹yvec ♯* AP› FrP have "yvec ♯* ΨP"
          by(drule_tac extractFrameFreshChain) auto
        ultimately show ?case
          by(auto simp add: frameChainAppend[symmetric] freshChainAppend) (auto simp add: frameChainAppend intro: frameResChainPres frameResChainComm)
      next
        assume "(Ψ, R, T) ∈ ?X2"
        then obtain xvec yvec P Q where "T = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and "R = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        moreover obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "yvec ♯* AP" and "AP ♯* Q"
          by(rule freshFrame[where C="(Ψ, yvec, Q)"]) auto
        moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "yvec ♯* AQ" and "AQ ♯* AP" and "AQ ♯* ΨP"
          by(rule freshFrame[where C="(Ψ, yvec, AP, ΨP)"]) auto
        moreover from FrQ ‹AP ♯* Q› ‹AQ ♯* AP› have "AP ♯* ΨQ"
          by(auto dest: extractFrameFreshChain)
        moreover from ‹yvec ♯* P› ‹yvec ♯* AP› FrP have "yvec ♯* ΨP"
          by(drule_tac extractFrameFreshChain) auto
        ultimately show ?case
          by(auto simp add: frameChainAppend[symmetric] freshChainAppend) (auto simp add: frameChainAppend intro: frameResChainPres frameResChainComm)
      qed
    next
      case(cSim Ψ R T)
      let ?Y = "{(Ψ, P, Q) | Ψ P P' Q' Q. Ψ ⊳ P ∼ P' ∧ ((Ψ, P', Q') ∈ ?X ∨ Ψ ⊳ P' ∼ Q') ∧ Ψ ⊳ Q' ∼ Q}"
      from ‹eqvt ?X› have "eqvt ?Y" by blast
      have C1: "⋀Ψ R T y. ⟦(Ψ, R, T) ∈ ?Y; (y::name) ♯ Ψ⟧ ⟹ (Ψ, ⦇νy⦈R, ⦇νy⦈T) ∈ ?Y"
      proof -
        fix Ψ R T y
        assume "(Ψ, R, T) ∈ ?Y"
        then obtain R' T' where "Ψ ⊳ R ∼ R'" and "(Ψ, R', T') ∈ (?X ∪ bisim)" and "Ψ ⊳ T' ∼ T" by force
        assume "(y::name) ♯ Ψ"
        show "(Ψ, ⦇νy⦈R, ⦇νy⦈T) ∈ ?Y"
        proof(cases "(Ψ, R', T') ∈ ?X")
          assume "(Ψ, R', T') ∈ ?X"
          show ?thesis
          proof(cases "(Ψ, R', T') ∈ ?X1")
            assume "(Ψ, R', T') ∈ ?X1"
            then obtain xvec yvec P Q where R'eq: "R' = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and T'eq: "T' = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))"
              and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
              by auto
            from ‹Ψ ⊳ R ∼ R'› ‹y ♯ Ψ› have "Ψ ⊳ ⦇νy⦈R ∼ ⦇νy⦈R'" by(rule bisimResPres)
            moreover from ‹xvec ♯* Ψ› ‹y ♯ Ψ› ‹yvec ♯* P› ‹yvec ♯* Ψ› have "(Ψ, ⦇ν*(y#xvec)⦈⦇ν*yvec⦈(P ∥ Q), ⦇ν*(y#xvec)⦈(P ∥ (⦇ν*yvec⦈Q))) ∈ ?X1"
              by(force simp del: resChain.simps)
            with R'eq T'eq have "(Ψ, ⦇νy⦈R', ⦇νy⦈T') ∈ ?X ∪ bisim" by simp
            moreover from ‹Ψ ⊳ T' ∼ T› ‹y ♯ Ψ› have "Ψ ⊳ ⦇νy⦈T' ∼ ⦇νy⦈T" by(rule bisimResPres)
            ultimately show ?thesis by blast
          next
            assume "(Ψ, R', T') ∉ ?X1"
            with ‹(Ψ, R', T') ∈ ?X› have "(Ψ, R', T') ∈ ?X2" by blast
            then obtain xvec yvec P Q where T'eq: "T' = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and R'eq: "R' = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
              by auto
            from ‹Ψ ⊳ R ∼ R'› ‹y ♯ Ψ› have "Ψ ⊳ ⦇νy⦈R ∼ ⦇νy⦈R'" by(rule bisimResPres)
            moreover from ‹xvec ♯* Ψ› ‹y ♯ Ψ› ‹yvec ♯* P› ‹yvec ♯* Ψ› have "(Ψ, ⦇ν*(y#xvec)⦈(P ∥ (⦇ν*yvec⦈Q)), ⦇ν*(y#xvec)⦈(⦇ν*yvec⦈(P ∥ Q))) ∈ ?X2"
              by(force simp del: resChain.simps)
            with R'eq T'eq have "(Ψ, ⦇νy⦈R', ⦇νy⦈T') ∈ ?X ∪ bisim" by simp
            moreover from ‹Ψ ⊳ T' ∼ T› ‹y ♯ Ψ› have "Ψ ⊳ ⦇νy⦈T' ∼ ⦇νy⦈T" by(rule bisimResPres)
            ultimately show ?thesis by blast
          qed
        next
          assume "(Ψ, R', T') ∉ ?X"
          with ‹(Ψ, R', T') ∈ ?X ∪ bisim› have "Ψ ⊳ R' ∼ T'" by blast
          with ‹Ψ ⊳ R ∼ R'› ‹Ψ ⊳ T' ∼ T› ‹y ♯ Ψ› show ?thesis
            by(blast dest: bisimResPres)
        qed
      qed
      have C1': "⋀Ψ R T y. ⟦(Ψ, R, T) ∈ ?Y⋆; (y::name) ♯ Ψ⟧ ⟹ (Ψ, ⦇νy⦈R, ⦇νy⦈T) ∈ ?Y⋆"
      proof -
        fix Ψ R
          and T::"('a,'b,'c) psi"
          and y::name
        assume "(Ψ, R, T) ∈ ?Y⋆"
          and  "y ♯ Ψ"
        then show "(Ψ, ⦇νy⦈R, ⦇νy⦈T) ∈ ?Y⋆"
        proof(induct rule: rel_trancl.induct)
          case(r_into_rel_trancl Ψ P Q)
          then show ?case
            by (intro rel_trancl.intros(1)) (rule C1)
        next
          case(rel_trancl_into_rel_trancl Ψ P Q R)
          then show ?case
            using rel_trancl.intros(2) C1 by meson
        qed
      qed
      have C1'': "⋀Ψ R T yvec. ⟦(Ψ, R, T) ∈ ?Y⋆; (yvec::name list) ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*yvec⦈R, ⦇ν*yvec⦈T) ∈ ?Y⋆"
      proof -
        fix Ψ R T
          and yvec::"name list"
        assume "(Ψ, R, T) ∈ ?Y⋆"
          and  "yvec ♯* Ψ"
        then show "(Ψ, ⦇ν*yvec⦈R, ⦇ν*yvec⦈T) ∈ ?Y⋆"
          apply(induct yvec)
           apply simp
          unfolding resChain.simps
          by(rule C1') simp+
      qed
      have C2: "⋀y Ψ' R S zvec. ⟦y ♯ Ψ'; y ♯ R; zvec ♯* Ψ'⟧ ⟹ (Ψ', ⦇νy⦈(⦇ν*zvec⦈(R ∥ S)), ⦇ν*zvec⦈(R ∥ ⦇νy⦈S)) ∈ ?Y⋆"
      proof -
        fix   y::name
          and Ψ::'b
          and R::"('a,'b,'c) psi"
          and S::"('a,'b,'c) psi"
          and zvec::"name list"
        assume "y ♯ Ψ"
          and  "y ♯ R"
          and  "zvec ♯* Ψ"
        have "Ψ ⊳ ⦇νy⦈(⦇ν*zvec⦈(R ∥ S)) ∼ (⦇ν*zvec⦈(⦇νy⦈(R ∥ S)))"
          by(rule bisimResComm') fact+
        moreover have "(Ψ, (⦇ν*zvec⦈(⦇νy⦈(R ∥ S))), ⦇ν*zvec⦈(R ∥ ⦇νy⦈S)) ∈ ?X" using ‹y ♯ Ψ› ‹y ♯ R› ‹zvec ♯* Ψ›
          apply clarsimp
          apply(rule exI[where x=zvec])
          apply(rule exI[where x="[y]"])
          by auto
        moreover have "Ψ ⊳ ⦇ν*zvec⦈(R ∥ ⦇νy⦈S) ∼ ⦇ν*zvec⦈(R ∥ ⦇νy⦈S)"
          by(rule bisimReflexive)
        ultimately show "(Ψ, ⦇νy⦈(⦇ν*zvec⦈(R ∥ S)), ⦇ν*zvec⦈(R ∥ ⦇νy⦈S)) ∈ ?Y⋆"
          by blast
      qed
      have C2': "⋀y Ψ' R S zvec. ⟦y ♯ Ψ'; y ♯ R; zvec ♯* Ψ'⟧ ⟹ (Ψ', ⦇ν*zvec⦈(R ∥ ⦇νy⦈S), ⦇νy⦈(⦇ν*zvec⦈(R ∥ S))) ∈ ?Y⋆"
      proof -
        fix   y::name
          and Ψ::'b
          and R::"('a,'b,'c) psi"
          and S::"('a,'b,'c) psi"
          and zvec::"name list"
        assume "y ♯ Ψ"
          and  "y ♯ R"
          and  "zvec ♯* Ψ"
        have "Ψ ⊳ (⦇ν*zvec⦈(⦇νy⦈(R ∥ S))) ∼ ⦇νy⦈(⦇ν*zvec⦈(R ∥ S))"
          by(rule bisimSymmetric[OF bisimResComm']) fact+
        moreover have "(Ψ, ⦇ν*zvec⦈(R ∥ ⦇νy⦈S), (⦇ν*zvec⦈(⦇νy⦈(R ∥ S)))) ∈ ?X" using ‹y ♯ Ψ› ‹y ♯ R› ‹zvec ♯* Ψ›
          apply(intro UnI2)
          apply clarsimp
          apply(rule exI[where x=zvec])
          apply(rule exI[where x="[y]"])
          by auto
        moreover have "Ψ ⊳ ⦇ν*zvec⦈(R ∥ ⦇νy⦈S) ∼ ⦇ν*zvec⦈(R ∥ ⦇νy⦈S)"
          by(rule bisimReflexive)
        ultimately show "(Ψ, ⦇ν*zvec⦈(R ∥ ⦇νy⦈S), ⦇νy⦈(⦇ν*zvec⦈(R ∥ S))) ∈ ?Y⋆"
          by blast
      qed
      have C3: "⋀Ψ' zvec R y. ⟦y ♯ Ψ'; zvec ♯* Ψ'⟧ ⟹ (Ψ', ⦇νy⦈(⦇ν*zvec⦈R), ⦇ν*zvec⦈(⦇νy⦈R)) ∈ ?Y⋆"
      proof -
        fix   y::name
          and Ψ::'b
          and R::"('a,'b,'c) psi"
          and zvec::"name list"
        assume "y ♯ Ψ"
          and  "zvec ♯* Ψ"
        then have "Ψ ⊳ ⦇νy⦈(⦇ν*zvec⦈R) ∼ ⦇ν*zvec⦈(⦇νy⦈R)"
          by(rule bisimResComm')
        then show "(Ψ, ⦇νy⦈(⦇ν*zvec⦈R), ⦇ν*zvec⦈(⦇νy⦈R)) ∈ ?Y⋆"
          by(blast intro: bisimReflexive)
      qed
      have C4: "⋀Ψ' R S zvec. ⟦zvec ♯* R; zvec ♯* Ψ'⟧ ⟹ (Ψ', (⦇ν*zvec⦈(R ∥ S)), (R ∥ (⦇ν*zvec⦈S))) ∈ ?Y⋆"
      proof -
        fix   Ψ::'b
          and R::"('a,'b,'c) psi"
          and S::"('a,'b,'c) psi"
          and zvec::"name list"
        assume "zvec ♯* R"
          and  "zvec ♯* Ψ"
        then have "(Ψ, (⦇ν*zvec⦈(R ∥ S)), (R ∥ (⦇ν*zvec⦈S))) ∈ ?X"
          apply clarsimp
          apply(rule exI[where x="[]"])
          apply(rule exI[where x=zvec])
          by auto
        then show "(Ψ, (⦇ν*zvec⦈(R ∥ S)), (R ∥ (⦇ν*zvec⦈S))) ∈ ?Y⋆"
          by(blast intro: bisimReflexive)
      qed
      have C4': "⋀Ψ' R S zvec. ⟦zvec ♯* R; zvec ♯* Ψ'⟧ ⟹ (Ψ', (R ∥ (⦇ν*zvec⦈S)), (⦇ν*zvec⦈(R ∥ S))) ∈ ?Y⋆"
      proof -
        fix   Ψ::'b
          and R::"('a,'b,'c) psi"
          and S::"('a,'b,'c) psi"
          and zvec::"name list"
        assume "zvec ♯* R"
          and  "zvec ♯* Ψ"
        then have "(Ψ, (R ∥ (⦇ν*zvec⦈S)), (⦇ν*zvec⦈(R ∥ S))) ∈ ?X"
          apply(intro UnI2)
          apply clarsimp
          apply(rule exI[where x="[]"])
          apply(rule exI[where x=zvec])
          by auto
        then show "(Ψ, (R ∥ (⦇ν*zvec⦈S)), (⦇ν*zvec⦈(R ∥ S))) ∈ ?Y⋆"
          by(blast intro: bisimReflexive)
      qed
      {
        fix Ψ P Q R
        assume "Ψ ⊳ P ↝[?Y⋆] Q"
          and  "Ψ ⊳ Q ↝[?Y⋆] R"
        moreover note rel_trancl_eqvt[OF ‹eqvt ?Y›]
        moreover have "{(Ψ, P, R) | Ψ P R. ∃Q. (Ψ, P, Q) ∈ ?Y⋆ ∧ (Ψ, Q, R) ∈ ?Y⋆} ⊆ ?Y⋆"
          by(auto intro: rel_trancl_transitive)
        ultimately have  "Ψ ⊳ P ↝[?Y⋆] R"
          by(rule transitive)
      }
      note trans = this

      show ?case
      proof(cases "(Ψ, R, T) ∈ ?X1")
        assume "(Ψ, R, T) ∈ ?X1"
        then obtain xvec yvec P Q where Req: "R = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and Teq: "T = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        have "Ψ ⊳ ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q)) ↝[?Y⋆] ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))"
        proof -
          have "Ψ ⊳ ⦇ν*yvec⦈(P ∥ Q) ↝[?Y⋆] P ∥ (⦇ν*yvec⦈Q)" using ‹yvec ♯* Ψ› ‹yvec ♯* P›
          proof(induct yvec arbitrary: Q)
            case Nil show ?case
              unfolding resChain.simps
              by(rule monotonic[where A="?Y"]) (blast intro: reflexive bisimReflexive)+
          next
            case(Cons y yvec)
            then have "yvec ♯* P" and "yvec ♯* Ψ" and "y ♯ Ψ" and "y ♯ P"
              by simp+
            have "Ψ ⊳ ⦇ν*(y#yvec)⦈P ∥ Q ↝[?Y⋆] ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q))"
            proof -
              have "Ψ ⊳ ⦇ν*(y#yvec)⦈P ∥ Q ↝[bisim] ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q))"
                unfolding resChain.simps
                apply(rule bisimE)
                apply(rule bisimResComm')
                by fact+
              then have "Ψ ⊳ ⦇ν*(y#yvec)⦈P ∥ Q ↝[?Y] ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q))"
                apply -
                apply(drule monotonic[where B="?Y"])
                by auto (blast intro: bisimTransitive bisimReflexive)
              then show ?thesis
                apply -
                apply(drule monotonic[where B="?Y⋆"])
                by blast
            qed
            moreover have "Ψ ⊳ ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q)) ↝[?Y⋆] ⦇ν*yvec⦈(P ∥ ⦇νy⦈Q)"
            proof -
              have "Ψ ⊳ ⦇νy⦈(P ∥ Q) ↝[?Y⋆] P ∥ ⦇νy⦈Q"
                apply(rule scopeExtLeft)
                      apply fact
                     apply fact
                    apply(rule rel_trancl_eqvt)
                    apply fact
                   apply(blast intro: bisimReflexive)
                by fact+
              then show ?thesis using ‹yvec ♯* Ψ›
              proof(induct yvec)
                case Nil then show ?case by simp
              next
                case(Cons y' yvec)
                then show ?case
                  unfolding resChain.simps
                  apply -
                  apply(rule resPres[where Rel="?Y⋆" and Rel'="?Y⋆"])
                      apply simp
                     apply(rule rel_trancl_eqvt[OF ‹eqvt ?Y›])
                    apply simp
                   apply simp
                  by(rule C1'')
              qed
            qed
            moreover have "Ψ ⊳ ⦇ν*yvec⦈(P ∥ ⦇νy⦈Q) ↝[?Y⋆] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
              by(rule Cons) fact+
            moreover have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y⋆] P ∥ (⦇ν*(y#yvec)⦈Q)"
            proof -
              have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[bisim] P ∥ (⦇ν*(y#yvec)⦈Q)"
                unfolding resChain.simps
                apply(rule bisimE)
                apply(rule bisimParPresSym)
                apply(rule bisimSymmetric[OF bisimResComm'])
                by fact+
              then have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y] P ∥ (⦇ν*(y#yvec)⦈Q)"
                apply -
                apply(drule monotonic[where B="?Y"])
                by auto (blast intro: bisimTransitive bisimReflexive)
              then show ?thesis
                apply -
                apply(drule monotonic[where B="?Y⋆"])
                by blast
            qed
            moreover have "Ψ ⊳ ⦇ν*yvec⦈P ∥ ⦇νy⦈Q ↝[?Y⋆] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
              by(rule Cons) fact+
            moreover have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y⋆] P ∥ (⦇ν*(y#yvec)⦈Q)"
            proof -
              have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[bisim] P ∥ (⦇νy⦈(⦇ν*yvec⦈Q))"
                apply(rule bisimE)
                apply(rule bisimParPresSym)
                apply(rule bisimSymmetric[OF bisimResComm'])
                by fact+
              then have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y] P ∥ (⦇νy⦈(⦇ν*yvec⦈Q))"
                apply -
                apply(drule monotonic[where B="?Y"])
                by auto (blast intro: bisimTransitive bisimReflexive)
              then show ?thesis
                unfolding resChain.simps
                apply -
                apply(drule monotonic[where B="?Y⋆"])
                by blast
            qed
            ultimately show ?case
              by(blast dest: trans)
          qed
          then show ?thesis using ‹xvec ♯* Ψ›
            apply(induct xvec)
             apply simp
            unfolding resChain.simps
            apply(rule resPres)
                apply simp
               apply(rule rel_trancl_eqvt[OF ‹eqvt ?Y›])
              apply simp
             apply simp
            apply(rule C1'')
             apply simp
            by assumption
        qed
        then show ?case unfolding Req Teq
          by -
      next
        assume "(Ψ, R, T) ∉ ?X1"
        then have "(Ψ, R, T) ∈ ?X2" using ‹(Ψ, R, T) ∈ ?X› by blast
        then obtain xvec yvec P Q where Teq: "T = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and Req: "R = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        have "Ψ ⊳ ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q)) ↝[?Y⋆] ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))"
        proof -
          have "Ψ ⊳ P ∥ (⦇ν*yvec⦈Q) ↝[?Y⋆] ⦇ν*yvec⦈(P ∥ Q)" using ‹yvec ♯* P› ‹yvec ♯* Ψ›
          proof(induct yvec arbitrary: Q)
            case Nil show ?case
              unfolding resChain.simps
              by(rule monotonic[where A="?Y"]) (blast intro: reflexive bisimReflexive)+
          next
            case(Cons y yvec)
            then have "yvec ♯* P" and "yvec ♯* Ψ" and "y ♯ Ψ" and "y ♯ P"
              by simp+
            have "Ψ ⊳ ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q)) ↝[?Y⋆] ⦇ν*(y#yvec)⦈P ∥ Q"
            proof -
              have "Ψ ⊳ ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q)) ↝[bisim] ⦇ν*(y#yvec)⦈P ∥ Q"
                unfolding resChain.simps
                apply(rule bisimE)
                apply(rule bisimSymmetric[OF bisimResComm'])
                by fact+
              then have "Ψ ⊳ ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q)) ↝[?Y] ⦇ν*(y#yvec)⦈P ∥ Q"
                apply -
                apply(drule monotonic[where B="?Y"])
                by auto (blast intro: bisimTransitive bisimReflexive)
              then show ?thesis
                apply -
                apply(drule monotonic[where B="?Y⋆"])
                by blast
            qed
            moreover have "Ψ ⊳ ⦇ν*yvec⦈(P ∥ ⦇νy⦈Q) ↝[?Y⋆] ⦇ν*yvec⦈(⦇νy⦈(P ∥ Q))"
            proof -
              have "Ψ ⊳ P ∥ ⦇νy⦈Q ↝[?Y⋆] ⦇νy⦈(P ∥ Q)"
                apply(rule scopeExtRight)
                     apply fact
                    apply fact
                   apply(rule rel_trancl_eqvt)
                   apply fact
                  apply(blast intro: bisimReflexive)
                by fact+
              then show ?thesis using ‹yvec ♯* Ψ›
              proof(induct yvec)
                case Nil then show ?case by simp
              next
                case(Cons y' yvec)
                then show ?case
                  unfolding resChain.simps
                  apply -
                  apply(rule resPres[where Rel="?Y⋆" and Rel'="?Y⋆"])
                      apply simp
                     apply(rule rel_trancl_eqvt[OF ‹eqvt ?Y›])
                    apply simp
                   apply simp
                  by(rule C1'')
              qed
              moreover have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y⋆] ⦇ν*yvec⦈(P ∥ ⦇νy⦈Q)"
                by(rule Cons) fact+
              moreover have "Ψ ⊳ P ∥ (⦇ν*(y#yvec)⦈Q) ↝[?Y⋆] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
              proof -
                have "Ψ ⊳ P ∥ (⦇ν*(y#yvec)⦈Q) ↝[bisim] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
                  unfolding resChain.simps
                  apply(rule bisimE)
                  apply(rule bisimParPresSym)
                  apply(rule bisimResComm')
                  by fact+
                then have "Ψ ⊳ P ∥ (⦇ν*(y#yvec)⦈Q) ↝[?Y] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
                  apply -
                  apply(drule monotonic[where B="?Y"])
                  by auto (blast intro: bisimTransitive bisimReflexive)
                then show ?thesis
                  apply -
                  apply(drule monotonic[where B="?Y⋆"])
                  by blast
              qed
            qed
            moreover have "Ψ ⊳ P ∥ (⦇ν*yvec⦈(⦇νy⦈Q)) ↝[?Y⋆] ⦇ν*yvec⦈P ∥ ⦇νy⦈Q"
              by(rule Cons) fact+
            moreover have "Ψ ⊳ P ∥ (⦇ν*(y#yvec)⦈Q) ↝[?Y⋆] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
            proof -
              have "Ψ ⊳ P ∥ (⦇νy⦈(⦇ν*yvec⦈Q)) ↝[bisim] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
                apply(rule bisimE)
                apply(rule bisimParPresSym)
                apply(rule bisimResComm')
                by fact+
              then have "Ψ ⊳ P ∥ (⦇νy⦈(⦇ν*yvec⦈Q)) ↝[?Y] P ∥ (⦇ν*yvec⦈(⦇νy⦈Q))"
                apply -
                apply(drule monotonic[where B="?Y"])
                by auto (blast intro: bisimTransitive bisimReflexive)
              then show ?thesis
                unfolding resChain.simps
                apply -
                apply(drule monotonic[where B="?Y⋆"])
                by blast
            qed
            ultimately show ?case
              by(blast dest: trans)
          qed
          then show ?thesis using ‹xvec ♯* Ψ›
            apply(induct xvec)
             apply simp
            unfolding resChain.simps
            apply(rule resPres)
                apply simp
               apply(rule rel_trancl_eqvt[OF ‹eqvt ?Y›])
              apply simp
             apply simp
            apply(rule C1'')
             apply simp
            by assumption
        qed
        then show ?case unfolding Req Teq
          by -
      qed
    next
      case(cExt Ψ R T Ψ')
      show ?case
      proof(cases "(Ψ, R, T) ∈ ?X1")
        assume "(Ψ, R, T) ∈ ?X1"
        then obtain xvec yvec P Q where Req: "R = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and Teq: "T = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        obtain p where "(p ∙ yvec) ♯* Ψ" and "(p ∙ yvec) ♯* P" and "(p ∙ yvec) ♯* Q" and "(p ∙ yvec) ♯* Ψ'" and "(p ∙ yvec) ♯* xvec"
          and S: "(set p) ⊆ (set yvec) × (set(p ∙ yvec))" and "distinctPerm p"
          by(rule name_list_avoiding[where c="(Ψ, P, Q, xvec, Ψ')"]) auto
        obtain q where "(q ∙ xvec) ♯* Ψ" and "(q ∙ xvec) ♯* Ψ'" and "(q ∙ xvec) ♯* P"  and "(q ∙ xvec) ♯* yvec" and "(q ∙ xvec) ♯* Q" and "(q ∙ xvec) ♯* (p∙P)" and "(q ∙ xvec) ♯* (p∙Q)" and "distinctPerm q" and T: "(set q) ⊆ (set xvec) × (set(q∙xvec))" and "(q ∙ xvec) ♯* (p∙yvec)"
          by(rule name_list_avoiding[where c="(Ψ, P, Q, yvec, p∙yvec, Ψ',p∙P,p∙Q)"]) auto
        note ‹(p ∙ yvec) ♯* Q› ‹set p ⊆ set yvec × set (p ∙ yvec)›
        moreover have "(p ∙ yvec) ♯* (P ∥ Q)" using ‹(p ∙ yvec) ♯* Q› ‹(p ∙ yvec) ♯* P›
          by simp
        moreover have "(Ψ ⊗ Ψ', ⦇ν*xvec⦈⦇ν*p ∙ yvec⦈p ∙ P ∥ Q, ⦇ν*xvec⦈P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q)) ∈ ?X"
        proof -
          have Pdef: "(p ∙ P) = P" using ‹set p ⊆ set yvec × set(p∙yvec)› ‹yvec ♯* P› ‹(p∙yvec) ♯* P›
            by simp
          have yvecdef: "(q ∙ p ∙ yvec) = (p∙ yvec)" using ‹set q ⊆ set xvec × set(q∙xvec)› ‹(p∙yvec) ♯* xvec› ‹(q∙xvec) ♯* (p∙yvec)›
            by simp
          have "(q ∙ xvec) ♯* (P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q))" using ‹(q ∙ xvec) ♯* P› ‹(q ∙ xvec) ♯* (p∙Q)› ‹(q ∙ xvec) ♯* (p∙yvec)›
            by simp
          moreover have "(q ∙ xvec) ♯* (⦇ν*p ∙ yvec⦈p ∙ P ∥ Q)"
            unfolding eqvts Pdef
            using ‹(q ∙ xvec) ♯* P› ‹(q ∙ xvec) ♯* (p∙Q)› ‹(q ∙ xvec) ♯* (p∙yvec)›
            by simp
          moreover note ‹set q ⊆ set xvec × set (q ∙ xvec)›
          moreover have "(Ψ ⊗ Ψ', ⦇ν*q ∙ xvec⦈q ∙ ⦇ν*p ∙ yvec⦈p ∙ P ∥ Q,
            ⦇ν*q ∙ xvec⦈q ∙ P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q)) ∈ ?X"
          proof -
            have "(p∙yvec) ♯* (Ψ⊗Ψ')" using ‹(p∙yvec) ♯* Ψ› ‹(p∙yvec) ♯* Ψ'›
              by auto
            moreover have "(p∙yvec) ♯* (q∙P)" using ‹(p∙yvec) ♯* P›
              apply(subst yvecdef[symmetric])
              by(subst fresh_star_bij)
            moreover have "(q∙xvec) ♯* (Ψ⊗Ψ')" using ‹(q∙xvec) ♯* Ψ› ‹(q∙xvec) ♯* Ψ'›
              by auto
            ultimately show ?thesis
              unfolding Pdef eqvts yvecdef
              by blast
          qed
          ultimately show ?thesis
            by(subst (1 2) resChainAlpha[where p=q and xvec=xvec])
        qed
        ultimately show ?case unfolding Req Teq
          apply(intro disjI1)
          by(subst (1 2) resChainAlpha[where p=p and xvec=yvec])
      next
        assume "(Ψ, R, T) ∉ ?X1"
        then have "(Ψ, R, T) ∈ ?X2" using ‹(Ψ,R,T) ∈ ?X›
          by blast
        then obtain xvec yvec P Q where Teq: "T = ⦇ν*xvec⦈(⦇ν*yvec⦈(P ∥ Q))" and Req: "R = ⦇ν*xvec⦈(P ∥ (⦇ν*yvec⦈Q))" and "xvec ♯* Ψ" and "yvec ♯* P" and "yvec ♯* Ψ"
          by auto
        obtain p where "(p ∙ yvec) ♯* Ψ" and "(p ∙ yvec) ♯* P" and "(p ∙ yvec) ♯* Q" and "(p ∙ yvec) ♯* Ψ'" and "(p ∙ yvec) ♯* xvec"
          and S: "(set p) ⊆ (set yvec) × (set(p ∙ yvec))" and "distinctPerm p"
          by(rule name_list_avoiding[where c="(Ψ, P, Q, xvec, Ψ')"]) auto
        obtain q where "(q ∙ xvec) ♯* Ψ" and "(q ∙ xvec) ♯* Ψ'" and "(q ∙ xvec) ♯* P"  and "(q ∙ xvec) ♯* yvec" and "(q ∙ xvec) ♯* Q" and "(q ∙ xvec) ♯* (p∙P)" and "(q ∙ xvec) ♯* (p∙Q)" and "distinctPerm q" and T: "(set q) ⊆ (set xvec) × (set(q∙xvec))" and "(q ∙ xvec) ♯* (p∙yvec)"
          by(rule name_list_avoiding[where c="(Ψ, P, Q, yvec, p∙yvec, Ψ',p∙P,p∙Q)"]) auto
        note ‹(p ∙ yvec) ♯* Q› ‹set p ⊆ set yvec × set (p ∙ yvec)›
        moreover have "(p ∙ yvec) ♯* (P ∥ Q)" using ‹(p ∙ yvec) ♯* Q› ‹(p ∙ yvec) ♯* P›
          by simp
        moreover have "(Ψ ⊗ Ψ', ⦇ν*xvec⦈P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q), ⦇ν*xvec⦈⦇ν*p ∙ yvec⦈p ∙ P ∥ Q) ∈ ?X"
        proof -
          have Pdef: "(p ∙ P) = P" using ‹set p ⊆ set yvec × set(p∙yvec)› ‹yvec ♯* P› ‹(p∙yvec) ♯* P›
            by simp
          have yvecdef: "(q ∙ p ∙ yvec) = (p∙ yvec)" using ‹set q ⊆ set xvec × set(q∙xvec)› ‹(p∙yvec) ♯* xvec› ‹(q∙xvec) ♯* (p∙yvec)›
            by simp
          have "(q ∙ xvec) ♯* (P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q))" using ‹(q ∙ xvec) ♯* P› ‹(q ∙ xvec) ♯* (p∙Q)› ‹(q ∙ xvec) ♯* (p∙yvec)›
            by simp
          moreover have "(q ∙ xvec) ♯* (⦇ν*p ∙ yvec⦈p ∙ P ∥ Q)"
            unfolding eqvts Pdef
            using ‹(q ∙ xvec) ♯* P› ‹(q ∙ xvec) ♯* (p∙Q)› ‹(q ∙ xvec) ♯* (p∙yvec)›
            by simp
          moreover note ‹set q ⊆ set xvec × set (q ∙ xvec)›
          moreover have "(Ψ ⊗ Ψ', ⦇ν*q ∙ xvec⦈q ∙ P ∥ (⦇ν*p ∙ yvec⦈p ∙ Q), ⦇ν*q ∙ xvec⦈q ∙ ⦇ν*p ∙ yvec⦈p ∙ P ∥ Q) ∈ ?X"
          proof -
            have "(p∙yvec) ♯* (Ψ⊗Ψ')" using ‹(p∙yvec) ♯* Ψ› ‹(p∙yvec) ♯* Ψ'›
              by auto
            moreover have "(p∙yvec) ♯* (q∙P)" using ‹(p∙yvec) ♯* P›
              apply(subst yvecdef[symmetric])
              by(subst fresh_star_bij)
            moreover have "(q∙xvec) ♯* (Ψ⊗Ψ')" using ‹(q∙xvec) ♯* Ψ› ‹(q∙xvec) ♯* Ψ'›
              by auto
            ultimately show ?thesis
              unfolding Pdef eqvts yvecdef
              by blast
          qed
          ultimately show ?thesis
            by(subst (1 2) resChainAlpha[where p=q and xvec=xvec])
        qed
        ultimately show ?case unfolding Req Teq
          apply(intro disjI1)
          by(subst (1 2) resChainAlpha[where p=p and xvec=yvec])
      qed
    next
      case(cSym Ψ P Q)
      then show ?case
        by(blast dest: bisimE)
    qed
  }
  moreover obtain y::name where "y ♯ Ψ" and "y ♯ P" "y ♯ Q"
    by(generate_fresh "name") auto
  ultimately have "Ψ ⊳ ⦇νy⦈(P ∥ ([(x, y)] ∙ Q)) ∼ P ∥ ⦇νy⦈([(x, y)] ∙ Q)" by auto
  then show ?thesis using assms ‹y ♯ P› ‹y ♯ Q›
    apply(subst alphaRes[where x=x and y=y and P=Q], auto)
    by(subst alphaRes[where x=x and y=y and P="P ∥ Q"]) auto
qed

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

assumes "xvec ♯* Ψ"
  and   "xvec ♯* P"

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

lemma bisimParAssoc:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"
    and R :: "('a, 'b, 'c) psi"

shows "Ψ ⊳ (P ∥ Q) ∥ R ∼ P ∥ (Q ∥ R)"
proof -
  let ?X = "{(Ψ, ⦇ν*xvec⦈((P ∥ Q) ∥ R), ⦇ν*xvec⦈(P ∥ (Q ∥ R))) | Ψ xvec P Q R. xvec ♯* Ψ}"
  let ?Y = "{(Ψ, P, Q) | Ψ P P' Q' Q. Ψ ⊳ P ∼ P' ∧ (Ψ, P', Q') ∈ ?X ∧ Ψ ⊳ Q' ∼ Q}"

  have "(Ψ, (P ∥ Q) ∥ R, P ∥ (Q ∥ R)) ∈ ?X"
    by(clarsimp, rule exI[where x="[]"]) auto
  moreover have "eqvt ?X" by(force simp add: eqvt_def simp add: pt_fresh_star_bij[OF pt_name_inst, OF at_name_inst] eqvts)
  ultimately show ?thesis
  proof(coinduct rule: weakTransitiveCoinduct')
    case(cStatEq Ψ PQR PQR')
    from ‹(Ψ, PQR, PQR') ∈ ?X› obtain xvec P Q R where "xvec ♯* Ψ" and "PQR = ⦇ν*xvec⦈((P ∥ Q) ∥ R)" and "PQR' = ⦇ν*xvec⦈(P ∥ (Q ∥ R))"
      by auto
    moreover obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" and "AP ♯* Q" and "AP ♯* R"
      by(rule freshFrame[where C="(Ψ, Q, R)"]) auto
    moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* AP" and "AQ ♯* ΨP" and "AQ ♯* R"
      by(rule freshFrame[where C="(Ψ, AP, ΨP, R)"]) auto
    moreover obtain AR ΨR where FrR: "extractFrame R = ⟨AR, ΨR⟩" and "AR ♯* Ψ" and "AR ♯* AP" and "AR ♯* ΨP" and "AR ♯* AQ" and "AR ♯* ΨQ"
      by(rule freshFrame[where C="(Ψ, AP, ΨP, AQ, ΨQ)"]) auto
    moreover from FrQ ‹AP ♯* Q› ‹AQ ♯* AP› have "AP ♯* ΨQ"
      by(auto dest: extractFrameFreshChain)
    moreover from FrR ‹AP ♯* R› ‹AR ♯* AP› have "AP ♯* ΨR"
      by(auto dest: extractFrameFreshChain)
    moreover from FrR ‹AQ ♯* R› ‹AR ♯* AQ› have "AQ ♯* ΨR"
      by(auto dest: extractFrameFreshChain)
    ultimately show ?case using freshCompChain
      by auto (metis frameChainAppend compositionSym Associativity frameNilStatEq frameResChainPres)
  next
    case(cSim Ψ T S)
    from ‹(Ψ, T, S) ∈ ?X› obtain xvec P Q R where "xvec ♯* Ψ" and TEq: "T = ⦇ν*xvec⦈((P ∥ Q) ∥ R)"
      and SEq: "S = ⦇ν*xvec⦈(P ∥ (Q ∥ R))"
      by auto
    from ‹eqvt ?X›have "eqvt ?Y" by blast
    have C1: "⋀Ψ T S yvec. ⟦(Ψ, T, S) ∈ ?Y; yvec ♯* Ψ⟧ ⟹ (Ψ, ⦇ν*yvec⦈T, ⦇ν*yvec⦈S) ∈ ?Y"
    proof -
      fix Ψ T S yvec
      assume "(Ψ, T, S) ∈ ?Y"
      then obtain T' S' where "Ψ ⊳ T ∼ T'" and "(Ψ, T', S') ∈ ?X" and "Ψ ⊳ S' ∼ S" by force
      assume "(yvec::name list) ♯* Ψ"
      from ‹(Ψ, T', S') ∈ ?X› obtain xvec P Q R where T'eq: "T' = ⦇ν*xvec⦈((P ∥ Q) ∥ R)" and S'eq: "S' = ⦇ν*xvec⦈(P ∥ (Q ∥ R))"
        and "xvec ♯* Ψ"
        by auto
      from ‹Ψ ⊳ T ∼ T'› ‹yvec ♯* Ψ› have "Ψ ⊳ ⦇ν*yvec⦈T ∼ ⦇ν*yvec⦈T'" by(rule bisimResChainPres)
      moreover from ‹xvec ♯* Ψ› ‹yvec ♯* Ψ› have "(Ψ, ⦇ν*(yvec@xvec)⦈((P ∥ Q) ∥ R), ⦇ν*(yvec@xvec)⦈(P ∥ (Q ∥ R))) ∈ ?X"
        by force
      with T'eq S'eq have "(Ψ, ⦇ν*yvec⦈T', ⦇ν*yvec⦈S') ∈ ?X" by(simp add: resChainAppend)
      moreover from ‹Ψ ⊳ S' ∼ S› ‹yvec ♯* Ψ› have "Ψ ⊳ ⦇ν*yvec⦈S' ∼ ⦇ν*yvec⦈S" by(rule bisimResChainPres)
      ultimately show "(Ψ, ⦇ν*yvec⦈T, ⦇ν*yvec⦈S) ∈ ?Y" by blast
    qed

    {
      fix y
      have "⋀Ψ T S. ⟦(Ψ, T, S) ∈ ?Y; y ♯ Ψ⟧ ⟹ (Ψ, ⦇νy⦈T, ⦇νy⦈S) ∈ ?Y"
        by(drule C1[where yvec2="[y]"]) auto
    }
    note C2 = this

    have "Ψ ⊳ ⦇ν*xvec⦈((P ∥ Q) ∥ R) ↝[?Y] ⦇ν*xvec⦈(P ∥ (Q ∥ R))"
    proof -
      have "Ψ ⊳ (P ∥ Q) ∥ R ↝[?Y] P ∥ (Q ∥ R)"
      proof -
        note ‹eqvt ?Y›
        moreover have "⋀Ψ P Q R. (Ψ, (P ∥ Q) ∥ R, P ∥ (Q ∥ R)) ∈ ?Y"
        proof -
          fix Ψ P Q R
          have "(Ψ::'b, ((P::('a, 'b, 'c) psi) ∥ Q) ∥ R, P ∥ (Q ∥ R)) ∈ ?X"
            by(clarsimp, rule exI[where x="[]"]) auto
          then show "(Ψ, (P ∥ Q) ∥ R, P ∥ (Q ∥ R)) ∈ ?Y"
            by(blast intro: bisimReflexive)
        qed
        moreover have "⋀xvec Ψ P Q R. ⟦xvec ♯* Ψ; xvec ♯* P⟧ ⟹ (Ψ, ⦇ν*xvec⦈((P ∥ Q) ∥ R), P ∥ (⦇ν*xvec⦈(Q ∥ R))) ∈ ?Y"
        proof -
          fix xvec Ψ P Q R
          assume "(xvec::name list) ♯* (Ψ::'b)" and "xvec ♯* (P::('a, 'b, 'c) psi)"
          from ‹xvec ♯* Ψ› have "(Ψ, ⦇ν*xvec⦈((P ∥ Q) ∥ R), ⦇ν*xvec⦈(P ∥ (Q ∥ R))) ∈ ?X" by blast
          moreover from ‹xvec ♯* Ψ› ‹xvec ♯* P› have "Ψ ⊳ ⦇ν*xvec⦈(P ∥ (Q ∥ R)) ∼ P ∥ (⦇ν*xvec⦈(Q ∥ R))"
            by(rule bisimScopeExtChain)
          ultimately show "(Ψ, ⦇ν*xvec⦈((P ∥ Q) ∥ R), P ∥ (⦇ν*xvec⦈(Q ∥ R))) ∈ ?Y"
            by(blast intro: bisimReflexive)
        qed
        moreover have "⋀xvec Ψ P Q R. ⟦xvec ♯* Ψ; xvec ♯* R⟧ ⟹ (Ψ, (⦇ν*xvec⦈(P ∥ Q)) ∥ R, ⦇ν*xvec⦈(P ∥ (Q ∥ R))) ∈ ?Y"
        proof -
          fix xvec Ψ P Q R
          assume "(xvec::name list) ♯* (Ψ::'b)" and "xvec ♯* (R::('a, 'b, 'c) psi)"
          have "Ψ ⊳ (⦇ν*xvec⦈(P ∥ Q)) ∥ R ∼ R ∥ (⦇ν*xvec⦈(P ∥ Q))" by(rule bisimParComm)
          moreover from ‹xvec ♯* Ψ› ‹xvec ♯* R› have "Ψ ⊳ ⦇ν*xvec⦈(R ∥ (P ∥ Q)) ∼ R ∥ (⦇ν*xvec⦈(P ∥ Q))" by(rule bisimScopeExtChain)
          then have "Ψ ⊳ R ∥ (⦇ν*xvec⦈(P ∥ Q)) ∼ ⦇ν*xvec⦈(R ∥ (P ∥ Q))" by(rule bisimE)
          moreover from ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(R ∥ (P ∥ Q)) ∼ ⦇ν*xvec⦈((P ∥ Q) ∥ R)"
            by(metis bisimResChainPres bisimParComm)
          moreover from ‹xvec ♯* Ψ› have "(Ψ, ⦇ν*xvec⦈((P ∥ Q) ∥ R), ⦇ν*xvec⦈(P ∥ (Q ∥ R))) ∈ ?X" by blast
          ultimately show "(Ψ, (⦇ν*xvec⦈(P ∥ Q)) ∥ R, ⦇ν*xvec⦈(P ∥ (Q ∥ R))) ∈ ?Y"  by(blast dest: bisimTransitive intro: bisimReflexive)
        qed
        ultimately show ?thesis using C1
          by(rule parAssocLeft)
      qed
      then show ?thesis using ‹eqvt ?Y› ‹xvec ♯* Ψ› C1
        by(rule resChainPres)
    qed
    with TEq SEq show ?case by simp
  next
    case(cExt Ψ T S Ψ')
    from ‹(Ψ, T, S) ∈ ?X› obtain xvec P Q R where "xvec ♯* Ψ" and TEq: "T = ⦇ν*xvec⦈((P ∥ Q) ∥ R)"
      and SEq: "S = ⦇ν*xvec⦈(P ∥ (Q ∥ R))"
      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 ∙ xvec) ♯* Ψ'› have "(Ψ ⊗ Ψ', ⦇ν*(p ∙ xvec)⦈(((p ∙ P) ∥ (p ∙ Q)) ∥ (p ∙ R)), ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ ((p ∙ Q) ∥ (p ∙ R)))) ∈ ?X"
      by auto
    moreover from TEq ‹(p ∙ xvec) ♯* P› ‹(p ∙ xvec) ♯* Q› ‹(p ∙ xvec) ♯* R› S have "T = ⦇ν*(p ∙ xvec)⦈(((p ∙ P) ∥ (p ∙ Q)) ∥ (p ∙ R))"
      apply clarsimp by(subst resChainAlpha[of p]) auto
    moreover from SEq ‹(p ∙ xvec) ♯* P› ‹(p ∙ xvec) ♯* Q› ‹(p ∙ xvec) ♯* R› S have "S = ⦇ν*(p ∙ xvec)⦈((p ∙ P) ∥ ((p ∙ Q) ∥ (p ∙ R)))"
      apply clarsimp by(subst resChainAlpha[of p]) auto
    ultimately show ?case by simp
  next
    case(cSym Ψ T S)
    from ‹(Ψ, T, S) ∈ ?X› obtain xvec P Q R where "xvec ♯* Ψ" and TEq: "T = ⦇ν*xvec⦈((P ∥ Q) ∥ R)"
      and SEq: "⦇ν*xvec⦈(P ∥ (Q ∥ R)) = S"
      by auto

    from ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(P ∥ (Q ∥ R)) ∼ ⦇ν*xvec⦈((R ∥ Q) ∥ P)"
      by(metis bisimParComm bisimParPres bisimTransitive bisimResChainPres)
    moreover from ‹xvec ♯* Ψ› have "(Ψ, ⦇ν*xvec⦈((R ∥ Q) ∥ P), ⦇ν*xvec⦈(R ∥ (Q ∥ P))) ∈ ?X" by blast
    moreover from ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(R ∥ (Q ∥ P)) ∼ ⦇ν*xvec⦈((P ∥ Q) ∥ R)"
      by(metis bisimParComm bisimParPres bisimTransitive bisimResChainPres)
    ultimately show ?case using TEq SEq by(blast dest: bisimTransitive)
  qed
qed

lemma bisimParNil:
  fixes P :: "('a, 'b, 'c) psi"

shows "Ψ ⊳ P ∥ 𝟬 ∼ P"
proof -
  let ?X1 = "{(Ψ, P ∥ 𝟬, P) | Ψ P. True}"
  let ?X2 = "{(Ψ, P, P ∥ 𝟬) | Ψ P. True}"
  let ?X = "?X1 ∪ ?X2"
  have "eqvt ?X" by(auto simp add: eqvt_def)
  have "(Ψ, P ∥ 𝟬, P) ∈ ?X" by simp
  then show ?thesis
  proof(coinduct rule: bisimWeakCoinduct)
    case(cStatEq Ψ Q R)
    show ?case
    proof(cases "(Ψ, Q, R) ∈ ?X1")
      assume "(Ψ, Q, R) ∈ ?X1"
      then obtain P where "Q = P ∥ 𝟬" and "R = P" by auto
      moreover obtain AP ΨP where "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ"
        by(rule freshFrame)
      ultimately show ?case
        apply clarsimp by(metis frameResChainPres frameNilStatEq Identity Associativity AssertionStatEqTrans Commutativity)
    next
      assume "(Ψ, Q, R) ∉ ?X1"
      with ‹(Ψ, Q, R) ∈ ?X› have "(Ψ, Q, R) ∈ ?X2" by blast
      then obtain P where "Q = P" and "R = P ∥ 𝟬" by auto
      moreover obtain AP ΨP where "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ"
        by(rule freshFrame)
      ultimately show ?case
        apply clarsimp by(metis frameResChainPres frameNilStatEq Identity Associativity AssertionStatEqTrans AssertionStatEqSym Commutativity)
    qed
  next
    case(cSim Ψ Q R)
    then show ?case using ‹eqvt ?X›
      by(auto intro: parNilLeft parNilRight)
  next
    case(cExt Ψ Q R Ψ')
    then show ?case by auto
  next
    case(cSym Ψ Q R)
    then show ?case by auto
  qed
qed

lemma bisimResNil:
  fixes x :: name
    and Ψ :: 'b

shows "Ψ ⊳ ⦇νx⦈𝟬 ∼ 𝟬"
proof -
  {
    fix x::name
    assume "x ♯ Ψ"
    have "Ψ ⊳ ⦇νx⦈𝟬 ∼ 𝟬"
    proof -
      let ?X1 = "{(Ψ, ⦇νx⦈𝟬, 𝟬) | Ψ x. x ♯ Ψ}"
      let ?X2 = "{(Ψ, 𝟬, ⦇νx⦈𝟬) | Ψ x. x ♯ Ψ}"
      let ?X = "?X1 ∪ ?X2"

      from ‹x ♯ Ψ› have "(Ψ, ⦇νx⦈𝟬, 𝟬) ∈ ?X" by auto
      then show ?thesis
      proof(coinduct rule: bisimWeakCoinduct)
        case(cStatEq Ψ P Q)
        then show ?case using freshComp by(force intro: frameResFresh FrameStatEqSym)
      next
        case(cSim Ψ P Q)
        then show ?case
          by(force intro: resNilLeft resNilRight)
      next
        case(cExt Ψ P Q Ψ')
        obtain y where "y ♯ Ψ" and "y ♯ Ψ'" and "y ≠ x"
          by(generate_fresh "name") (auto simp add: fresh_prod)
        show ?case
        proof(cases "(Ψ, P, Q) ∈ ?X1")
          assume "(Ψ, P, Q) ∈ ?X1"
          then obtain x where "P = ⦇νx⦈𝟬" and "Q = 𝟬" by auto
          moreover have "⦇νx⦈𝟬 = ⦇νy⦈ 𝟬" by(subst alphaRes) auto
          ultimately show ?case using ‹y ♯ Ψ› ‹y ♯ Ψ'› by auto
        next
          assume "(Ψ, P, Q) ∉ ?X1"
          with ‹(Ψ, P, Q) ∈ ?X› have "(Ψ, P, Q) ∈ ?X2" by auto
          then obtain x where "Q = ⦇νx⦈𝟬" and "P = 𝟬" by auto
          moreover have "⦇νx⦈𝟬 = ⦇νy⦈ 𝟬" by(subst alphaRes) auto
          ultimately show ?case using ‹y ♯ Ψ› ‹y ♯ Ψ'› by auto
        qed
      next
        case(cSym Ψ P Q)
        then show ?case by auto
      qed
    qed
  }
  moreover obtain y::name where "y ♯ Ψ" by(generate_fresh "name") auto
  ultimately have "Ψ ⊳ ⦇νy⦈𝟬 ∼ 𝟬" by auto
  then show ?thesis by(subst alphaRes[where x=x and y=y]) auto
qed

lemma bisimOutputPushRes:
  fixes x :: name
    and Ψ :: 'b
    and M :: 'a
    and N :: 'a
    and P :: "('a, 'b, 'c) psi"

assumes "x ♯ M"
  and   "x ♯ N"

shows "Ψ ⊳ ⦇νx⦈(M⟨N⟩.P) ∼ M⟨N⟩.⦇νx⦈P"
proof -
  {
    fix x::name and P::"('a, 'b, 'c) psi"
    assume "x ♯ Ψ" and "x ♯ M" and "x ♯ N"
    let ?X1 = "{(Ψ, ⦇νx⦈(M⟨N⟩.P), M⟨N⟩.⦇νx⦈P) | Ψ x M N P. x ♯ Ψ ∧ x ♯ M ∧ x ♯ N}"
    let ?X2 = "{(Ψ, M⟨N⟩.⦇νx⦈P, ⦇νx⦈(M⟨N⟩.P)) | Ψ x M N P. x ♯ Ψ ∧ x ♯ M ∧ x ♯ N}"
    let ?X = "?X1 ∪ ?X2"

    have "eqvt ?X"
      by(rule eqvtUnion) (force simp add: eqvt_def pt_fresh_bij[OF pt_name_inst, OF at_name_inst] eqvts)+
    from ‹x ♯ Ψ› ‹x ♯ M› ‹x ♯ N› have "(Ψ, ⦇νx⦈(M⟨N⟩.P), M⟨N⟩.⦇νx⦈P) ∈ ?X"
      by auto
    then have "Ψ ⊳ ⦇νx⦈(M⟨N⟩.P) ∼ M⟨N⟩.⦇νx⦈P"
    proof(coinduct rule: bisimCoinduct)
      case(cStatEq Ψ Q R)
      then show ?case using freshComp by(force intro: frameResFresh FrameStatEqSym)
    next
      case(cSim Ψ Q R)
      then show ?case using ‹eqvt ?X›
        by(auto intro!: outputPushResLeft outputPushResRight bisimReflexive)
    next
      case(cExt Ψ Q R Ψ')
      show ?case
      proof(cases "(Ψ, Q, R) ∈ ?X1")
        assume "(Ψ, Q, R) ∈ ?X1"
        then obtain x M N P where Qeq: "Q = ⦇νx⦈(M⟨N⟩.P)" and Req: "R = M⟨N⟩.⦇νx⦈P" and "x ♯ Ψ" and "x ♯ M" and "x ♯ N" by auto
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ M" and "y ♯ N" and "y ♯ P"
          by(generate_fresh "name") (auto simp add: fresh_prod)

        moreover then have "(Ψ ⊗ Ψ', ⦇νy⦈(M⟨N⟩.([(x, y)] ∙ P)), M⟨N⟩.⦇νy⦈([(x, y)] ∙ P)) ∈ ?X" by auto
        moreover from Qeq ‹x ♯ M› ‹y ♯ M› ‹x ♯ N› ‹y ♯ N› ‹y ♯ P› have "Q = ⦇νy⦈(M⟨N⟩.([(x, y)] ∙ P))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        moreover from Req ‹y ♯ P› have "R = M⟨N⟩.⦇νy⦈([(x, y)] ∙ P)"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        ultimately show ?case by blast
      next
        assume "(Ψ, Q, R) ∉ ?X1"
        with ‹(Ψ, Q, R) ∈ ?X› have "(Ψ, Q, R) ∈ ?X2" by blast
        then obtain x M N P where Req: "R = ⦇νx⦈(M⟨N⟩.P)" and Qeq: "Q = M⟨N⟩.⦇νx⦈P" and "x ♯ Ψ" and "x ♯ M" and "x ♯ N" by auto
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ M" and "y ♯ N" and "y ♯ P"
          by(generate_fresh "name") (auto simp add: fresh_prod)

        moreover then have "(Ψ ⊗ Ψ', ⦇νy⦈(M⟨N⟩.([(x, y)] ∙ P)), M⟨N⟩.⦇νy⦈([(x, y)] ∙ P)) ∈ ?X" by auto
        moreover from Req ‹x ♯ M› ‹y ♯ M› ‹x ♯ N› ‹y ♯ N› ‹y ♯ P› have "R = ⦇νy⦈(M⟨N⟩.([(x, y)] ∙ P))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        moreover from Qeq ‹y ♯ P› have "Q = M⟨N⟩.⦇νy⦈([(x, y)] ∙ P)"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        ultimately show ?case by blast
      qed
    next
      case(cSym Ψ R Q)
      then show ?case by blast
    qed
  }
  moreover obtain y::name where "y ♯ Ψ" and "y ♯ M" and "y ♯ N" "y ♯ P"
    by(generate_fresh "name") auto
  ultimately have "Ψ ⊳ ⦇νy⦈(M⟨N⟩.([(x, y)] ∙ P)) ∼ M⟨N⟩.⦇νy⦈([(x, y)] ∙ P)" by auto
  then show ?thesis using assms ‹y ♯ P› ‹y ♯ M› ‹y ♯ N›
    apply(subst alphaRes[where x=x and y=y and P=P], auto)
    by(subst alphaRes[where x=x and y=y and P="M⟨N⟩.P"]) auto
qed

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

assumes "x ♯ M"
  and   "x ♯ xvec"
  and   "x ♯ N"

shows "Ψ ⊳ ⦇νx⦈(M⦇λ*xvec N⦈.P) ∼ M⦇λ*xvec N⦈.⦇νx⦈P"
proof -
  {
    fix x::name and P::"('a, 'b, 'c) psi"
    assume "x ♯ Ψ" and "x ♯ M" and "x ♯ N" and "x ♯ xvec"
    let ?X1 = "{(Ψ, ⦇νx⦈(M⦇λ*xvec N⦈.P), M⦇λ*xvec N⦈.⦇νx⦈P) | Ψ x M xvec N P. x ♯ Ψ ∧ x ♯ M ∧ x ♯ xvec ∧ x ♯ N}"
    let ?X2 = "{(Ψ, M⦇λ*xvec N⦈.⦇νx⦈P, ⦇νx⦈(M⦇λ*xvec N⦈.P)) | Ψ x M xvec N P. x ♯ Ψ ∧ x ♯ M ∧ x ♯ xvec ∧ x ♯ N}"
    let ?X = "?X1 ∪ ?X2"

    have "eqvt ?X"
      by(rule eqvtUnion) (force simp add: eqvt_def pt_fresh_bij[OF pt_name_inst, OF at_name_inst] eqvts)+

    from ‹x ♯ Ψ› ‹x ♯ M› ‹x ♯ xvec› ‹x ♯ N› have "(Ψ, ⦇νx⦈(M⦇λ*xvec N⦈.P), M⦇λ*xvec N⦈.⦇νx⦈P) ∈ ?X"
      by blast
    then have "Ψ ⊳ ⦇νx⦈(M⦇λ*xvec N⦈.P) ∼ M⦇λ*xvec N⦈.⦇νx⦈P"
    proof(coinduct rule: bisimCoinduct)
      case(cStatEq Ψ Q R)
      then show ?case using freshComp by(force intro: frameResFresh FrameStatEqSym)
    next
      case(cSim Ψ Q R)
      then show ?case using ‹eqvt ?X›
        by(auto intro!: inputPushResLeft inputPushResRight bisimReflexive)
    next
      case(cExt Ψ Q R Ψ')
      show ?case
      proof(cases "(Ψ, Q, R) ∈ ?X1")
        assume "(Ψ, Q, R) ∈ ?X1"
        then obtain x M xvec N P where Qeq: "Q = ⦇νx⦈(M⦇λ*xvec N⦈.P)" and Req: "R = M⦇λ*xvec N⦈.⦇νx⦈P" and "x ♯ Ψ"
          and "x ♯ M" and "x ♯ xvec" and "x ♯ N" by auto
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ M" and "y ♯ N" and "y ♯ P" and "y ♯ xvec"
          by(generate_fresh "name") (auto simp add: fresh_prod)

        moreover then have "(Ψ ⊗ Ψ', ⦇νy⦈(M⦇λ*xvec N⦈.([(x, y)] ∙ P)), M⦇λ*xvec N⦈.⦇νy⦈([(x, y)] ∙ P)) ∈ ?X" by force
        moreover from Qeq ‹x ♯ M› ‹y ♯ M› ‹x ♯ xvec› ‹y ♯ xvec› ‹x ♯ N› ‹y ♯ N› ‹y ♯ P› have "Q = ⦇νy⦈(M⦇λ*xvec N⦈.([(x, y)] ∙ P))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts inputChainFresh)
        moreover from Req ‹y ♯ P› have "R = M⦇λ*xvec N ⦈.⦇νy⦈([(x, y)] ∙ P)"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        ultimately show ?case by blast
      next
        assume "(Ψ, Q, R) ∉ ?X1"
        with ‹(Ψ, Q, R) ∈ ?X› have "(Ψ, Q, R) ∈ ?X2" by blast
        then obtain x M xvec N P where Req: "R = ⦇νx⦈(M⦇λ*xvec N⦈.P)" and Qeq: "Q = M⦇λ*xvec N⦈.⦇νx⦈P" and "x ♯ Ψ"
          and "x ♯ M" and "x ♯ xvec" and "x ♯ N" by auto
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ M" and "y ♯ N" and "y ♯ P" and "y ♯ xvec"
          by(generate_fresh "name") (auto simp add: fresh_prod)

        moreover then have "(Ψ ⊗ Ψ', ⦇νy⦈(M⦇λ*xvec N⦈.([(x, y)] ∙ P)), M⦇λ*xvec N⦈.⦇νy⦈([(x, y)] ∙ P)) ∈ ?X" by force
        moreover from Req ‹x ♯ M› ‹y ♯ M› ‹x ♯ xvec› ‹y ♯ xvec› ‹x ♯ N› ‹y ♯ N› ‹y ♯ P› have "R = ⦇νy⦈(M⦇λ*xvec N⦈.([(x, y)] ∙ P))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts inputChainFresh)
        moreover from Qeq ‹y ♯ P› have "Q = M⦇λ*xvec N ⦈.⦇νy⦈([(x, y)] ∙ P)"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        ultimately show ?case by blast
      qed
    next
      case(cSym Ψ R Q)
      then show ?case by blast
    qed
  }
  moreover obtain y::name where "y ♯ Ψ" and "y ♯ M" and "y ♯ N" and "y ♯ P" and "y ♯ xvec"
    by(generate_fresh "name") auto
  ultimately have "Ψ ⊳ ⦇νy⦈(M⦇λ*xvec N⦈.([(x, y)] ∙ P)) ∼ M⦇λ*xvec N⦈.⦇νy⦈([(x, y)] ∙ P)" by auto
  then show ?thesis using assms ‹y ♯ P› ‹y ♯ M› ‹y ♯ N› ‹y ♯ xvec›
    apply(subst alphaRes[where x=x and y=y and P=P], auto)
    by(subst alphaRes[where x=x and y=y and P="M⦇λ*xvec N⦈.P"]) (auto simp add: inputChainFresh eqvts)
qed

lemma bisimCasePushRes:
  fixes x  :: name
    and Ψ  :: 'b
    and Cs :: "('c × ('a, 'b, 'c) psi) list"

assumes "x ♯ (map fst Cs)"

shows "Ψ ⊳ ⦇νx⦈(Cases Cs) ∼ Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)"
proof -
  {
    fix x::name and Cs::"('c × ('a, 'b, 'c) psi) list"
    assume "x ♯ Ψ" and "x ♯ (map fst Cs)"
    let ?X1 = "{(Ψ, ⦇νx⦈(Cases Cs), Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)) | Ψ x Cs. x ♯ Ψ ∧ x ♯ (map fst Cs)}"
    let ?X2 = "{(Ψ, Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs), ⦇νx⦈(Cases Cs)) | Ψ x Cs. x ♯ Ψ ∧ x ♯ (map fst Cs)}"
    let ?X = "?X1 ∪ ?X2"

    have "eqvt ?X"
    proof
      show "eqvt ?X1"
        apply(clarsimp simp add: eqvt_def eqvts)
        apply (rule exI)
        apply (rule exI)
        apply (rule conjI)
         apply (rule refl)
        apply(perm_extend_simp)
          apply(clarsimp simp add: eqvts)
         apply (simp add: fresh_bij)
        apply(drule pt_fresh_bij1[OF pt_name_inst, OF at_name_inst])
        apply(drule pt_fresh_bij1[OF pt_name_inst, OF at_name_inst])
       apply(simp add: eqvts)
        apply(perm_extend_simp)
        apply(simp add: eqvts)
        done
    next
      show "eqvt ?X2"
        apply(clarsimp simp add: eqvt_def eqvts)
        apply (rule exI)
        apply (rule exI)
        apply (subst conj_commute)
        apply (rule conjI)
        apply (rule conjI)
          apply (rule refl)
         apply(perm_extend_simp)
          apply (simp add: fresh_bij)
         apply(drule pt_fresh_bij1[OF pt_name_inst, OF at_name_inst])
         apply(drule pt_fresh_bij1[OF pt_name_inst, OF at_name_inst])
         apply(simp add: eqvts)
         apply(perm_extend_simp)
         apply(simp add: eqvts)
        apply(perm_extend_simp)
        apply(clarsimp simp add: eqvts)
        done
    qed

    from ‹x ♯ Ψ› ‹x ♯ map fst Cs› have "(Ψ, ⦇νx⦈(Cases Cs), Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)) ∈ ?X" by auto
    then have "Ψ ⊳ ⦇νx⦈(Cases Cs) ∼ Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)"
    proof(coinduct rule: bisimCoinduct)
      case(cStatEq Ψ Q R)
      then show ?case using freshComp by(force intro: frameResFresh FrameStatEqSym)
    next
      case(cSim Ψ Q R)
      then show ?case using ‹eqvt ?X›
        by(auto intro!: casePushResLeft casePushResRight bisimReflexive)
    next
      case(cExt Ψ Q R Ψ')
      show ?case
      proof(cases "(Ψ, Q, R) ∈ ?X1")
        assume "(Ψ, Q, R) ∈ ?X1"
        then obtain x Cs where Qeq: "Q = ⦇νx⦈(Cases Cs)" and Req: "R = Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)"
          and "x ♯ Ψ" and "x ♯ (map fst Cs)" by blast
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ Cs"
          by(generate_fresh "name") (auto simp add: fresh_prod)
        from ‹y ♯ Cs› ‹x ♯ (map fst Cs)› have "y ♯ map fst ([(x, y)] ∙ Cs)" by(induct Cs) (auto simp add: fresh_list_cons fresh_list_nil)

        moreover with ‹y ♯ Ψ› ‹y ♯ Ψ'› have "(Ψ ⊗ Ψ', ⦇νy⦈(Cases ([(x, y)] ∙ Cs)), Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs))) ∈ ?X"
          by auto
        moreover from Qeq ‹y ♯ Cs› have "Q = ⦇νy⦈(Cases([(x, y)] ∙ Cs))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        moreover from Req ‹y ♯ Cs› ‹x ♯ (map fst Cs)› have "R = Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs))"
          by(induct Cs arbitrary: R) (auto simp add: fresh_list_cons fresh_prod alphaRes)
        ultimately show ?case by blast
      next
        assume "(Ψ, Q, R) ∉ ?X1"
        with ‹(Ψ, Q, R) ∈ ?X› have "(Ψ, Q, R) ∈ ?X2" by blast
        then obtain x Cs where Req: "R = ⦇νx⦈(Cases Cs)" and Qeq: "Q = Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)"
          and "x ♯ Ψ" and "x ♯ (map fst Cs)" by blast
        obtain y::name where "y ♯ Ψ" and "y ♯ Ψ'" and "y ♯ Cs"
          by(generate_fresh "name") (auto simp add: fresh_prod)
        from ‹y ♯ Cs› ‹x ♯ (map fst Cs)› have "y ♯ map fst ([(x, y)] ∙ Cs)" by(induct Cs) (auto simp add: fresh_list_cons fresh_list_nil)

        moreover with ‹y ♯ Ψ› ‹y ♯ Ψ'› have "(Ψ ⊗ Ψ', ⦇νy⦈(Cases ([(x, y)] ∙ Cs)), Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs))) ∈ ?X"
          by auto
        moreover from Req ‹y ♯ Cs› have "R = ⦇νy⦈(Cases([(x, y)] ∙ Cs))"
          apply clarsimp by(subst alphaRes[of y]) (auto simp add: eqvts)
        moreover from Qeq ‹y ♯ Cs› ‹x ♯ (map fst Cs)› have "Q = Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs))"
          by(induct Cs arbitrary: Q) (auto simp add: fresh_list_cons fresh_prod alphaRes)
        ultimately show ?case by blast
      qed
    next
      case(cSym Ψ R Q)
      then show ?case by blast
    qed
  }
  moreover obtain y::name where "y ♯ Ψ" and "y ♯ Cs" by(generate_fresh "name") auto
  moreover from ‹x ♯ map fst Cs› have "y ♯ map fst([(x, y)] ∙ Cs)"
    by(induct Cs) (auto simp add: fresh_left calc_atm)
  ultimately have "Ψ ⊳ ⦇νy⦈(Cases ([(x, y)] ∙ Cs)) ∼ Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs))"
    by auto
  moreover from ‹y ♯ Cs› have "⦇νy⦈(Cases ([(x, y)] ∙ Cs)) =  ⦇νx⦈(Cases Cs)"
    by(simp add: alphaRes eqvts)
  moreover from ‹x ♯ map fst Cs› ‹y ♯ Cs› have "Cases(map (λ(φ, P). (φ, ⦇νy⦈P)) ([(x, y)] ∙ Cs)) = Cases(map (λ(φ, P). (φ, ⦇νx⦈P)) Cs)"
    by(induct Cs) (auto simp add: alphaRes)
  ultimately show ?thesis by auto
qed

lemma bangExt:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"

assumes "guarded P"

shows "Ψ ⊳ !P ∼ P ∥ !P"
proof -
  let ?X = "{(Ψ, !P, P ∥ !P) | Ψ P. guarded P} ∪ {(Ψ, P ∥ !P, !P) | Ψ P. guarded P}"
  from ‹guarded P› have "(Ψ, !P, P ∥ !P) ∈ ?X" by auto
  then show ?thesis
  proof(coinduct rule: bisimCoinduct)
    case(cStatEq Ψ Q R)
    from ‹(Ψ, Q, R) ∈ ?X› obtain P where Eq: "(Q = !P ∧ R = P ∥ !P) ∨ (Q = P ∥ !P ∧ R = !P)" and "guarded P"
      by auto
    obtain AP ΨP where FrP: "extractFrame P = ⟨AP, ΨP⟩" and "AP ♯* Ψ" by(rule freshFrame)
    from FrP ‹guarded P› have "ΨP ≃ SBottom'" by(blast dest: guardedStatEq)
    from ‹ΨP ≃ SBottom'› have "Ψ ⊗ SBottom' ≃ Ψ ⊗ ΨP ⊗ SBottom'" by(metis Identity Composition AssertionStatEqTrans Commutativity AssertionStatEqSym)
    then have "⟨AP, Ψ ⊗ SBottom'⟩ ≃F ⟨AP, Ψ ⊗ ΨP ⊗ SBottom'⟩"
      by(force intro: frameResChainPres)
    moreover from ‹AP ♯* Ψ› have "⟨ε, Ψ ⊗ SBottom'⟩ ≃F ⟨AP, Ψ ⊗ SBottom'⟩"
      apply -
      by(rule FrameStatEqSym) (simp add: frameResFreshChain freshCompChain(1))
    ultimately show ?case using Eq ‹AP ♯* Ψ› FrP
      by auto (blast dest: FrameStatEqTrans FrameStatEqSym)+
  next
    case(cSim Ψ Q R)
    then show ?case by(auto intro: bangExtLeft bangExtRight bisimReflexive)
  next
    case(cExt Ψ Q R)
    then show ?case by auto
  next
    case(cSym Ψ Q R)
    then show ?case by auto
  qed
qed

lemma bisimScopeExtSym:
  fixes x :: name
    and Q :: "('a, 'b, 'c) psi"
    and P :: "('a, 'b, 'c) psi"

assumes "x ♯ Ψ"
  and   "x ♯ Q"

shows "Ψ ⊳ ⦇νx⦈(P ∥ Q) ∼ (⦇νx⦈P) ∥ Q"
  using assms
  by(metis bisimScopeExt bisimTransitive bisimParComm bisimSymmetric bisimResPres)

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

assumes "xvec ♯* Ψ"
  and   "xvec ♯* Q"

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

lemma bisimParPresAuxSym:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"
    and R :: "('a, 'b, 'c) psi"

assumes "Ψ ⊗ ΨR ⊳ P ∼ Q"
  and   "extractFrame R = ⟨AR, ΨR⟩"
  and   "AR ♯* Ψ"
  and   "AR ♯* P"
  and   "AR ♯* Q"

shows "Ψ ⊳ R ∥ P ∼ R ∥ Q"
  using assms
  by(metis bisimParComm bisimParPresAux bisimTransitive)

lemma bangDerivative:
  fixes Ψ   :: 'b
    and P    :: "('a, 'b, 'c) psi"
    and α    :: "'a action"
    and P'   :: "('a, 'b, 'c) psi"

assumes "Ψ ⊳ !P ⟼α ≺ P'"
  and   "Ψ ⊳ P ∼ Q"
  and   "bn α ♯* Ψ"
  and   "bn α ♯* P"
  and   "bn α ♯* Q"
  and   "bn α ♯* subject α"
  and   "guarded Q"

obtains Q' R T where "Ψ ⊳ !Q ⟼α ≺ Q'" and "Ψ ⊳ P' ∼ R ∥ !P" and "Ψ ⊳ Q' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T"
  and "((supp R)::name set) ⊆ supp P'" and "((supp T)::name set) ⊆ supp Q'"
proof -
  from ‹Ψ ⊳ !P ⟼α ≺ P'› have "guarded P"
    apply -
    by(ind_cases "Ψ ⊳ !P ⟼α ≺ P'") (auto simp add: psi.inject)
  assume "⋀Q' R T. ⟦Ψ ⊳ !Q ⟼α ≺ Q'; Ψ ⊳ P' ∼ R ∥ !P; Ψ ⊳ Q' ∼ T ∥ !Q; Ψ ⊳ R ∼ T; ((supp R)::name set) ⊆ supp P';
                    ((supp T)::name set) ⊆ supp Q'⟧ ⟹ thesis"
  moreover from ‹Ψ ⊳ !P ⟼α ≺ P'› ‹bn α ♯* subject α› ‹bn α ♯* Ψ› ‹bn α ♯* P› ‹bn α ♯* Q› ‹Ψ ⊳ P ∼ Q› ‹guarded Q›
  have "∃Q' T R . Ψ ⊳ !Q ⟼α  ≺ Q' ∧ Ψ ⊳ P' ∼ R ∥ !P ∧ Ψ ⊳ Q' ∼ T ∥ !Q ∧ Ψ ⊳ R ∼ T ∧
                  ((supp R)::name set) ⊆ supp P' ∧ ((supp T)::name set) ⊆ supp Q'"
  proof(nominal_induct avoiding: Q rule: bangInduct')
    case(cAlpha α P' p Q)
    then obtain Q' T R where QTrans: "Ψ ⊳ !Q ⟼α ≺ Q'" and "Ψ ⊳ P' ∼ R ∥ (P ∥ !P)" and "Ψ ⊳ Q' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T"
      and suppR: "((supp R)::name set) ⊆ supp P'" and suppT: "((supp T)::name set) ⊆ supp Q'"
      by blast
    from QTrans have "distinct(bn α)"
      by(rule boundOutputDistinct)
    have S: "set p ⊆ set(bn α) × set(bn(p ∙ α))"
      by fact
    from QTrans ‹bn(p ∙ α) ♯* Q› ‹bn(p ∙ α) ♯* α› ‹bn α ♯* subject α› ‹distinct(bn α)› have "bn(p ∙ α) ♯* Q'"
      by(drule_tac freeFreshChainDerivative) simp+
    with QTrans ‹bn(p ∙ α) ♯* α› S ‹bn α ♯* subject α› have "Ψ ⊳ !Q ⟼(p ∙ α) ≺ (p ∙ Q')"
      by(force simp add: residualAlpha)
    moreover from ‹Ψ ⊳ P' ∼ R ∥ (P ∥ !P)› have "(p ∙ Ψ) ⊳ (p ∙ P') ∼ (p ∙ (R ∥ (P ∥ !P)))"
      by(rule bisimClosed)
    with ‹bn α ♯* Ψ› ‹bn α ♯* P› ‹bn(p ∙ α) ♯* Ψ› ‹bn(p ∙ α) ♯* P› S have "Ψ ⊳ (p ∙ P') ∼ (p ∙ R) ∥ (P ∥ !P)"
      by(simp add: eqvts)
    moreover from ‹Ψ ⊳ Q' ∼ T ∥ !Q› have "(p ∙ Ψ) ⊳ (p ∙ Q') ∼ (p ∙ (T ∥ !Q))"
      by(rule bisimClosed)
    with ‹bn α ♯* Ψ› ‹bn α ♯* Q› ‹bn(p ∙ α) ♯* Ψ› ‹bn(p ∙ α) ♯* Q› S have "Ψ ⊳ (p ∙ Q') ∼ (p ∙ T) ∥ !Q"
      by(simp add: eqvts)
    moreover from ‹Ψ ⊳ R ∼ T› have "(p ∙ Ψ) ⊳ (p ∙ R) ∼ (p ∙ T)"
      by(rule bisimClosed)
    with ‹bn α ♯* Ψ› ‹bn(p ∙ α) ♯* Ψ› S have "Ψ ⊳ (p ∙ R) ∼ (p ∙ T)"
      by(simp add: eqvts)
    moreover from suppR have "((supp(p ∙ R))::name set) ⊆ supp(p ∙ P')"
      apply(erule_tac rev_mp)
      by(subst subsetClosed[of p, symmetric]) (simp add: eqvts)
    moreover from suppT have "((supp(p ∙ T))::name set) ⊆ supp(p ∙ Q')"
      apply(erule_tac rev_mp)
      by(subst subsetClosed[of p, symmetric]) (simp add: eqvts)
    ultimately show ?case by blast
  next
    case(cPar1 α P' Q)
    from ‹Ψ ⊳ P ∼ Q› ‹Ψ ⊳ P ⟼α ≺ P'› ‹bn α ♯* Ψ› ‹bn α ♯* Q›
    obtain Q' where QTrans: "Ψ ⊳ Q ⟼α ≺ Q'" and "Ψ ⊳ P' ∼ Q'"
      by(blast dest: bisimE simE)
    from QTrans have "Ψ ⊗ SBottom' ⊳ Q ⟼α ≺ Q'"
      by(metis statEqTransition Identity AssertionStatEqSym)
    then have "Ψ ⊳ Q ∥ !Q ⟼α ≺ (Q' ∥ !Q)"
      using ‹bn α ♯* Q› by(intro Par1) (assumption | simp)+
    then have "Ψ ⊳ !Q ⟼α ≺ (Q' ∥ !Q)"
      using ‹guarded Q› by(rule Bang)
    moreover from ‹guarded P› have "Ψ ⊳ P' ∥ !P ∼ P' ∥ (P ∥ !P)"
      by(metis bangExt bisimParPresSym)
    moreover have "Ψ ⊳ Q' ∥ !Q ∼ Q' ∥ !Q"
      by(rule bisimReflexive)
    ultimately show ?case using ‹Ψ ⊳ P' ∼ Q'›
      by(force simp add: psi.supp)
  next
    case(cPar2 α P' Q)
    then obtain Q' T R where QTrans: "Ψ ⊳ !Q ⟼α ≺ Q'" and "Ψ ⊳ P' ∼ R ∥ !P" and "Ψ ⊳ Q' ∼ T ∥ !Q"
      and "Ψ ⊳ R ∼ T" and suppR: "((supp R)::name set) ⊆ supp P'" and suppT: "((supp T)::name set) ⊆ supp Q'"
      by blast
    note QTrans
    from ‹Ψ ⊳ P' ∼ R ∥ !P› have "Ψ ⊳ P ∥ P' ∼ R ∥ (P ∥ !P)"
      by(metis bisimParPresSym bisimParComm bisimTransitive bisimParAssoc)
    with QTrans show ?case using ‹Ψ ⊳ Q' ∼ T ∥ !Q› ‹Ψ ⊳ R ∼ T› suppR suppT
      by(force simp add: psi.supp)
  next
    case(cComm1 M N P' K xvec P'' Q)
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊳ Q ↝[bisim] P"
      by(metis bisimE)
    with ‹Ψ ⊳ P ⟼M⦇N⦈ ≺ P'› obtain Q' where QTrans: "Ψ ⊳ Q ⟼M⦇N⦈ ≺ Q'" and "Ψ ⊳ Q' ∼ P'"
      by(force dest: simE)
    from QTrans have "Ψ ⊗ SBottom' ⊳ Q ⟼M⦇N⦈ ≺ Q'"
      by(metis statEqTransition Identity AssertionStatEqSym)
    moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* Q" and "AQ ♯* M"
      by(rule freshFrame[where C="(Ψ, Q, M)"]) auto
    note FrQ
    moreover from FrQ ‹guarded Q› have "ΨQ ≃ SBottom'"
      by(blast dest: guardedStatEq)
    from ‹Ψ ⊳ !P ⟼K⦇ν*xvec⦈⟨N⟩ ≺ P''› ‹xvec ♯* K› ‹Ψ ⊳ P ∼ Q› ‹xvec ♯* Ψ› ‹xvec ♯* P› ‹xvec ♯* Q› ‹guarded Q›
    obtain Q'' T R where QTrans': "Ψ ⊳ !Q ⟼K⦇ν*xvec⦈⟨N⟩ ≺ Q''" and "Ψ ⊳ P'' ∼ R ∥ !P" and "Ψ ⊳ Q'' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T"
      and suppR: "((supp R)::name set) ⊆ supp P''" and suppT: "((supp T)::name set) ⊆ supp Q''"
      using cComm1 by force
    from QTrans' ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊳ !Q ⟼K⦇ν*xvec⦈⟨N⟩ ≺ Q''"
      by(metis statEqTransition Identity compositionSym AssertionStatEqSym)
    moreover from ‹Ψ ⊢ M ↔ K› ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊗ SBottom' ⊢ M ↔ K"
      by(metis statEqEnt Identity compositionSym AssertionStatEqSym)
    ultimately have "Ψ ⊳ Q ∥ !Q ⟼τ ≺ (⦇ν*xvec⦈(Q' ∥ Q''))" using ‹AQ ♯* Ψ› ‹AQ ♯* Q› ‹AQ ♯* M› ‹xvec ♯* Q›
      by(intro Comm1) (assumption | simp)+
    then have "Ψ ⊳ !Q ⟼τ ≺ (⦇ν*xvec⦈(Q' ∥ Q''))"
      using ‹guarded Q› by(rule Bang)
    moreover from ‹Ψ ⊳ P'' ∼ R ∥ !P› ‹guarded P› ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ P'') ∼ ⦇ν*xvec⦈((P' ∥ R) ∥ (P ∥ !P))"
      by(metis bisimParPresSym bangExt bisimTransitive bisimParAssoc bisimSymmetric bisimResChainPres)
    with ‹xvec ♯* Ψ› ‹xvec ♯* P› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ P'') ∼ (⦇ν*xvec⦈(P' ∥ R)) ∥ (P ∥ !P)"
      by(metis bisimScopeExtChainSym bisimTransitive psiFreshVec)
    moreover from ‹Ψ ⊳ Q'' ∼ T ∥ !Q› ‹xvec ♯* Ψ› ‹xvec ♯* Q› have "Ψ ⊳ ⦇ν*xvec⦈(Q' ∥ Q'') ∼ (⦇ν*xvec⦈(Q' ∥ T)) ∥ !Q"
      by(metis bisimParPresSym bisimTransitive bisimParAssoc bisimSymmetric bisimResChainPres bisimScopeExtChainSym psiFreshVec)
    moreover from ‹Ψ ⊳ R ∼ T› ‹Ψ ⊳ Q' ∼ P'› ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ R) ∼ ⦇ν*xvec⦈(Q' ∥ T)"
      by(metis bisimParPresSym bisimTransitive bisimResChainPres bisimParComm bisimE(4))
    moreover from suppR have "((supp(⦇ν*xvec⦈(P' ∥ R)))::name set) ⊆  supp((⦇ν*xvec⦈(P' ∥ P'')))"
      by(auto simp add: psi.supp resChainSupp)
    moreover from suppT have "((supp(⦇ν*xvec⦈(Q' ∥ T)))::name set) ⊆  supp((⦇ν*xvec⦈(Q' ∥ Q'')))"
      by(auto simp add: psi.supp resChainSupp)
    ultimately show ?case by blast
  next
    case(cComm2 M xvec N P' K P'' Q)
    from ‹Ψ ⊳ P ∼ Q› ‹Ψ ⊳ P ⟼M⦇ν*xvec⦈⟨N⟩ ≺ P'› ‹xvec ♯* Ψ› ‹xvec ♯* Q›
    obtain Q' where QTrans: "Ψ ⊳ Q ⟼M⦇ν*xvec⦈⟨N⟩ ≺ Q'" and "Ψ ⊳ P' ∼ Q'"
      by(metis bisimE simE bn.simps)
    from QTrans have "Ψ ⊗ SBottom' ⊳ Q ⟼M⦇ν*xvec⦈⟨N⟩ ≺ Q'"
      by(metis statEqTransition Identity AssertionStatEqSym)
    moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* Q" and "AQ ♯* M"
      by(rule freshFrame[where C="(Ψ, Q, M)"]) auto
    note FrQ
    moreover from FrQ ‹guarded Q› have "ΨQ ≃ SBottom'"
      by(blast dest: guardedStatEq)
    from ‹Ψ ⊳ !P ⟼K⦇N⦈ ≺ P''› ‹Ψ ⊳ P ∼ Q› ‹guarded Q›
    obtain Q'' T R where QTrans': "Ψ ⊳ !Q ⟼K⦇N⦈ ≺ Q''" and "Ψ ⊳ P'' ∼ R ∥ !P" and "Ψ ⊳ Q'' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T"
      and suppR: "((supp R)::name set) ⊆ supp P''" and suppT: "((supp T)::name set) ⊆ supp Q''" using cComm2
      by force
    from QTrans' ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊳ !Q ⟼K⦇N⦈ ≺ Q''"
      by(metis statEqTransition Identity compositionSym AssertionStatEqSym)
    moreover from ‹Ψ ⊢ M ↔ K› ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊗ SBottom' ⊢ M ↔ K"
      by(metis statEqEnt Identity compositionSym AssertionStatEqSym)
    ultimately have "Ψ ⊳ Q ∥ !Q ⟼τ ≺ (⦇ν*xvec⦈(Q' ∥ Q''))" using ‹AQ ♯* Ψ› ‹AQ ♯* Q› ‹AQ ♯* M› ‹xvec ♯* Q›
      by(intro Comm2) (assumption | simp)+
    then have "Ψ ⊳ !Q ⟼τ ≺ (⦇ν*xvec⦈(Q' ∥ Q''))" using ‹guarded Q› by(rule Bang)
    moreover from ‹Ψ ⊳ P'' ∼ R ∥ !P› ‹guarded P› ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ P'') ∼ ⦇ν*xvec⦈((P' ∥ R) ∥ (P ∥ !P))"
      by(metis bisimParPresSym bangExt bisimTransitive bisimParAssoc bisimSymmetric bisimResChainPres)
    with ‹xvec ♯* Ψ› ‹xvec ♯* P› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ P'') ∼ (⦇ν*xvec⦈(P' ∥ R)) ∥ (P ∥ !P)"
      by(metis bisimScopeExtChainSym bisimTransitive psiFreshVec)
    moreover from ‹Ψ ⊳ Q'' ∼ T ∥ !Q› ‹xvec ♯* Ψ› ‹xvec ♯* Q› have "Ψ ⊳ ⦇ν*xvec⦈(Q' ∥ Q'') ∼ (⦇ν*xvec⦈(Q' ∥ T)) ∥ !Q"
      by(metis bisimParPresSym bisimTransitive bisimParAssoc bisimSymmetric bisimResChainPres bisimScopeExtChainSym psiFreshVec)
    moreover from ‹Ψ ⊳ R ∼ T› ‹Ψ ⊳ P' ∼ Q'› ‹xvec ♯* Ψ› have "Ψ ⊳ ⦇ν*xvec⦈(P' ∥ R) ∼ ⦇ν*xvec⦈(Q' ∥ T)"
      by(metis bisimParPresSym bisimTransitive bisimResChainPres bisimParComm)
    moreover from suppR have "((supp(⦇ν*xvec⦈(P' ∥ R)))::name set) ⊆  supp((⦇ν*xvec⦈(P' ∥ P'')))"
      by(auto simp add: psi.supp resChainSupp)
    moreover from suppT have "((supp(⦇ν*xvec⦈(Q' ∥ T)))::name set) ⊆  supp((⦇ν*xvec⦈(Q' ∥ Q'')))"
      by(auto simp add: psi.supp resChainSupp)
    ultimately show ?case by blast
  next
    case(cBang α P' Q)
    then obtain Q' T R where QTrans: "Ψ ⊳ !Q ⟼α ≺ Q'" and "Ψ ⊳ P' ∼ R ∥ (P ∥ !P)" and "Ψ ⊳ Q' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T"
      and suppR: "((supp R)::name set) ⊆ supp P'" and suppT: "((supp T)::name set) ⊆ supp Q'"
      by blast
    from ‹Ψ ⊳ P' ∼ R ∥ (P ∥ !P)› ‹guarded P› have "Ψ ⊳ P' ∼ R ∥ !P"
      by(metis bangExt bisimParPresSym bisimTransitive bisimSymmetric)
    with QTrans show ?case using ‹Ψ ⊳ Q' ∼ T ∥ !Q› ‹Ψ ⊳ R ∼ T› suppR suppT
      by blast
  next
    case(cBrMerge M N P' P'' Q)
    then obtain Q' T R where "Ψ ⊳ !Q ⟼ ¿M⦇N⦈ ≺ Q'" and
      p''eq: "Ψ ⊳ P'' ∼ R ∥ !P" and
      "Ψ ⊳ Q' ∼ T ∥ !Q" and "Ψ ⊳ R ∼ T" and
      "supp R ⊆ (supp P''::name set)" and
      "supp T ⊆ (supp Q'::name set)"
      by blast
    obtain Q'' where "Ψ ⊳ Q ⟼ ¿M⦇N⦈ ≺ Q''" and "Ψ ⊳ Q'' ∼ P'"
    proof -
      assume g: "(⋀Q''. ⟦Ψ ⊳ Q ⟼ ¿M⦇N⦈ ≺ Q''; Ψ ⊳ Q'' ∼ P'⟧ ⟹ thesis)"
      have "∃Q'. Ψ ⊳ Q ⟼ ¿M⦇N⦈ ≺ Q' ∧ (Ψ, Q', P') ∈ bisim"
        apply(rule simE)
           apply(rule bisimE)
           apply(rule bisimSymmetric)
        by fact+
      then show thesis
        using g by blast
    qed
    have "Ψ ⊗ 𝟭 ⊳ Q ⟼ ¿M⦇N⦈ ≺ Q''" using ‹Ψ ⊳ Q ⟼ ¿M⦇N⦈ ≺ Q''›
      by(rule statEqTransition) (rule AssertionStatEqSym[OF Identity])
    obtain AQ ΨQ where "extractFrame Q = ⟨AQ,ΨQ⟩" and "distinct AQ" and "AQ ♯* Ψ" and "AQ ♯* Q" and "AQ ♯* M"
      by(rule freshFrame[where C="(Ψ,Q,M)"]) force
    then have "ΨQ ≃ 𝟭" using ‹guarded Q›
      by(auto dest: guardedStatEq)
    have "Ψ ⊗ ΨQ ⊳ !Q ⟼ ¿M⦇N⦈ ≺ Q'" using ‹Ψ ⊳ !Q ⟼ ¿M⦇N⦈ ≺ Q'›
      by(rule statEqTransition) (metis ‹ΨQ ≃ 𝟭› AssertionStatEqTrans AssertionStatEqSym Identity compositionSym)
    have "Ψ ⊳ !Q ⟼ ¿M⦇N⦈ ≺ Q'' ∥ Q'"
      by(rule Bang) (rule BrMerge|fact|simp)+
    moreover have "Ψ ⊳ P' ∥ P'' ∼ (P' ∥ R) ∥ (P ∥ !P)"
      apply(rule bisimTransitive[OF bisimParPresSym, OF p''eq])
      apply(rule bisimTransitive[OF bisimSymmetric, OF bisimParAssoc])
      apply(rule bisimParPresSym)
      apply(rule bangExt[OF ‹guarded P›])
      done
    moreover have "Ψ ⊳ Q'' ∥ Q' ∼ Q'' ∥ T ∥ !Q" using ‹Ψ ⊳ Q' ∼ T ∥ !Q›
      by(metis bisimTransitive bisimParAssoc bisimParComm bisimParPres bisimSymmetric)
    moreover have "Ψ ⊳ (P' ∥ R) ∼ Q'' ∥ T" using ‹Ψ ⊳ R ∼ T› and ‹Ψ ⊳ Q'' ∼ P'›
      apply -
      apply(erule bisimTransitive[OF bisimParPres, OF bisimSymmetric])
      apply(erule bisimTransitive[OF bisimParPresSym])
      by(rule bisimReflexive)
    moreover have "supp(P' ∥ R) ⊆ (supp(P'∥P'')::name set)"
      using ‹supp R ⊆ (supp P''::name set)› by(auto simp add: psi.supp)
    moreover have "supp(Q'' ∥ T) ⊆ (supp(Q'' ∥ Q')::name set)"
      using ‹supp T ⊆ (supp Q'::name set)› by(auto simp add: psi.supp)
    ultimately show ?case
      by blast
  next
    case(cBrComm1 M N P' xvec P'' Q)
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊳ Q ↝[bisim] P" by(metis bisimE)
    with ‹Ψ ⊳ P ⟼¿M⦇N⦈ ≺ P'› obtain Q' where QTrans: "Ψ ⊳ Q ⟼¿M⦇N⦈ ≺ Q'" and "Ψ ⊳ Q' ∼ P'"
      by(force dest: simE)
    from QTrans have "Ψ ⊗ SBottom' ⊳ Q ⟼¿M⦇N⦈ ≺ Q'"
      by(metis statEqTransition Identity AssertionStatEqSym)
    moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* Q" and "AQ ♯* M"
      by(rule freshFrame[where C="(Ψ, Q, M)"]) auto
    note FrQ
    moreover from FrQ ‹guarded Q› have "ΨQ ≃ SBottom'"
      by(blast dest: guardedStatEq)
    from ‹Ψ ⊳ !P ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ P''› ‹Ψ ⊳ P ∼ Q› ‹xvec ♯* Ψ› ‹xvec ♯* P› ‹xvec ♯* Q› ‹guarded Q›
    obtain Q'' T R where QTrans': "Ψ ⊳ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q''" and "Ψ ⊳ P'' ∼ R ∥ !P" and "Ψ ⊳ Q'' ∼ T ∥ !Q"
      and "Ψ ⊳ R ∼ T" and suppR: "((supp R)::name set) ⊆ supp P''" and suppT: "((supp T)::name set) ⊆ supp Q''"
      using cBrComm1 by force
    from QTrans' ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊳ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q''"
      by(metis statEqTransition Identity compositionSym AssertionStatEqSym)
    ultimately have "Ψ ⊳ Q ∥ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q' ∥ Q''"
      using ‹AQ ♯* Ψ› ‹AQ ♯* Q› ‹AQ ♯* M› ‹xvec ♯* Q› by(intro BrComm1) (assumption | simp)+
    then have "Ψ ⊳ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q' ∥ Q''"
      using ‹guarded Q› by(rule Bang)
    moreover from ‹Ψ ⊳ P'' ∼ R ∥ !P› ‹guarded P› ‹xvec ♯* Ψ› have "Ψ ⊳ P' ∥ P'' ∼ (P' ∥ R) ∥ (P ∥ !P)"
      by(metis bisimParPresSym bangExt bisimTransitive bisimParAssoc bisimSymmetric)
    moreover from ‹Ψ ⊳ Q'' ∼ T ∥ !Q› ‹xvec ♯* Ψ› ‹xvec ♯* Q› have "Ψ ⊳ Q' ∥ Q'' ∼ (Q' ∥ T) ∥ !Q"
      by(metis bisimParPresSym bisimTransitive bisimParAssoc bisimSymmetric)
    moreover from ‹Ψ ⊳ R ∼ T› ‹Ψ ⊳ Q' ∼ P'› ‹xvec ♯* Ψ› have "Ψ ⊳ P' ∥ R ∼ Q' ∥ T"
      by(metis bisimParPresSym bisimTransitive bisimParComm bisimE(4))
    moreover from suppR have "((supp(P' ∥ R))::name set) ⊆  supp((P' ∥ P''))"
      by(auto simp add: psi.supp resChainSupp)
    moreover from suppT have "((supp(Q' ∥ T))::name set) ⊆  supp((Q' ∥ Q''))"
      by(auto simp add: psi.supp resChainSupp)
    ultimately show ?case by blast
  next
    case(cBrComm2 M N P' xvec P'' Q)
    from ‹Ψ ⊳ P ∼ Q› have "Ψ ⊳ Q ↝[bisim] P" by(metis bisimE)
    with ‹Ψ ⊳ P ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ P'› obtain Q' where QTrans: "Ψ ⊳ Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q'" and "Ψ ⊳ Q' ∼ P'"
      using ‹xvec ♯* Ψ› ‹xvec ♯* P› ‹xvec ♯* Q› by(auto dest: simE)
    from QTrans have "Ψ ⊗ SBottom' ⊳ Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q'"
      by(metis statEqTransition Identity AssertionStatEqSym)
    moreover obtain AQ ΨQ where FrQ: "extractFrame Q = ⟨AQ, ΨQ⟩" and "AQ ♯* Ψ" and "AQ ♯* Q" and "AQ ♯* M"
      by(rule freshFrame[where C="(Ψ, Q, M)"]) auto
    note FrQ
    moreover from FrQ ‹guarded Q› have "ΨQ ≃ SBottom'" by(blast dest: guardedStatEq)
    from ‹Ψ ⊳ !P ⟼¿M⦇N⦈ ≺ P''› ‹Ψ ⊳ P ∼ Q› ‹xvec ♯* Ψ› ‹xvec ♯* P› ‹xvec ♯* Q› ‹guarded Q›
    obtain Q'' T R where QTrans': "Ψ ⊳ !Q ⟼¿M⦇N⦈ ≺ Q''" and "Ψ ⊳ P'' ∼ R ∥ !P" and "Ψ ⊳ Q'' ∼ T ∥ !Q"
      and "Ψ ⊳ R ∼ T" and suppR: "((supp R)::name set) ⊆ supp P''" and suppT: "((supp T)::name set) ⊆ supp Q''"
      using cBrComm2 by force
    from QTrans' ‹ΨQ ≃ SBottom'› have "Ψ ⊗ ΨQ ⊳ !Q ⟼¿M⦇N⦈ ≺ Q''"
      by(metis statEqTransition Identity compositionSym AssertionStatEqSym)
    ultimately have "Ψ ⊳ Q ∥ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q' ∥ Q''"
      using ‹AQ ♯* Ψ› ‹AQ ♯* Q› ‹AQ ♯* M› ‹xvec ♯* Q› by(intro BrComm2) (assumption | simp)+
    then have "Ψ ⊳ !Q ⟼¡M⦇ν*xvec⦈⟨N⟩ ≺ Q' ∥ Q''"
      using ‹guarded Q› by(rule Bang)
    moreover from ‹Ψ ⊳ P'' ∼ R ∥ !P› ‹guarded P› ‹xvec ♯* Ψ› have "Ψ ⊳ P' ∥ P'' ∼ (P' ∥ R) ∥ (P ∥ !P)"
      by(metis bisimParPresSym bangExt bisimTransitive bisimParAssoc bisimSymmetric)
    moreover from ‹Ψ ⊳ Q'' ∼ T ∥ !Q› ‹xvec ♯* Ψ› ‹xvec ♯* Q› have "Ψ ⊳ Q' ∥ Q'' ∼ (Q' ∥ T) ∥ !Q"
      by(metis bisimParPresSym bisimTransitive bisimParAssoc bisimSymmetric)
    moreover from ‹Ψ ⊳ R ∼ T› ‹Ψ ⊳ Q' ∼ P'› ‹xvec ♯* Ψ› have "Ψ ⊳ P' ∥ R ∼ Q' ∥ T"
      by(metis bisimParPresSym bisimTransitive bisimParComm bisimE(4))
    moreover from suppR have "((supp(P' ∥ R))::name set) ⊆  supp((P' ∥ P''))"
      by(auto simp add: psi.supp resChainSupp)
    moreover from suppT have "((supp(Q' ∥ T))::name set) ⊆  supp((Q' ∥ Q''))"
      by(auto simp add: psi.supp resChainSupp)
    ultimately show ?case by blast
  qed
  ultimately show ?thesis by blast
qed

lemma structCongBisim:
  fixes P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"

assumes "P ≡s Q"

shows "P ∼ Q"
  using assms
  by(induct rule: structCong.induct)
    (auto intro: bisimReflexive bisimSymmetric bisimTransitive bisimParComm bisimParAssoc bisimParNil bisimResNil bisimResComm bisimScopeExt bisimCasePushRes bisimInputPushRes bisimOutputPushRes bangExt)

lemma bisimBangPres:
  fixes Ψ :: 'b
    and P :: "('a, 'b, 'c) psi"
    and Q :: "('a, 'b, 'c) psi"

assumes "Ψ ⊳ P ∼ Q"
  and   "guarded P"
  and   "guarded Q"

shows "Ψ ⊳ !P ∼ !Q"
proof -
  let ?X = "{(Ψ, R ∥ !P, R ∥ !Q) | Ψ P Q R. Ψ ⊳ P ∼ Q ∧ guarded P ∧ guarded Q}"
  let ?Y = "{(Ψ, P, Q) | Ψ P P' Q' Q. Ψ ⊳ P ∼ P' ∧ (Ψ, P', Q') ∈ ?X ∧ Ψ ⊳ Q' ∼ Q}"
  from assms have "(Ψ, 𝟬 ∥ !P, 𝟬 ∥ !Q) ∈ ?X" by(blast intro: bisimReflexive)

  moreover have "eqvt ?X"
    apply(clarsimp simp add: eqvt_def)
    apply(drule bisimClosed)
    by force
  ultimately have "Ψ ⊳ 𝟬 ∥ !P ∼ 𝟬 ∥ !Q"
  proof(coinduct rule: weakTransitiveCoinduct)
    case(cStatEq Ψ P Q)
    then show ?case by auto
  next
    case(cSim Ψ RP RQ)
    from ‹(Ψ, RP, RQ) ∈ ?X› obtain P Q R where "Ψ ⊳ P ∼ Q" and "guarded P" and "guarded Q"
      and "RP = R ∥ !P" and "RQ = R ∥ !Q"
      by auto
    note ‹Ψ ⊳ P ∼ Q›
    moreover from ‹eqvt ?X› have "eqvt ?Y" by blast
    moreover note ‹guarded P› ‹guarded Q› bisimE(2) bisimE(3) bisimE(4) statEqBisim bisimClosed bisimParAssoc[THEN bisimSymmetric]
      bisimParPres bisimParPresAuxSym bisimResChainPres bisimScopeExtChainSym bisimTransitive
    moreover have "⋀Ψ P Q R T. ⟦Ψ ⊳ P ∼ Q; (Ψ, Q, R) ∈ ?Y; Ψ ⊳ R ∼ T⟧ ⟹ (Ψ, P, T) ∈ ?Y"
      by auto (metis bisimTransitive)
    moreover have "⋀Ψ P Q R. ⟦Ψ ⊳ P ∼ Q; guarded P; guarded Q⟧ ⟹ (Ψ, R ∥ !P, R ∥ !Q) ∈ ?Y" by(blast intro: bisimReflexive)
    moreover have "⋀Ψ P α P' Q. ⟦Ψ ⊳ !P ⟼α ≺ P'; Ψ ⊳ P ∼ Q; bn α ♯* Ψ;  bn α ♯* P;  bn α ♯* Q; guarded Q; bn α ♯* subject α⟧ ⟹
                                         ∃Q' R T.  Ψ ⊳ !Q ⟼α ≺ Q' ∧ Ψ ⊳ P' ∼ R ∥ !P ∧  Ψ ⊳ Q' ∼ T ∥ !Q ∧
                                                   Ψ ⊳ R ∼ T ∧ ((supp R)::name set) ⊆ supp P' ∧
                                                   ((supp T)::name set) ⊆ supp Q'"
      by(blast elim: bangDerivative)
    ultimately have "Ψ ⊳ R ∥ !P ↝[?Y] R ∥ !Q"
      by(rule bangPres)
    with ‹RP = R ∥ !P› ‹RQ = R ∥ !Q› show ?case
      by blast
  next
    case(cExt Ψ RP RQ Ψ')
    then show ?case by(blast dest: bisimE)
  next
    case(cSym Ψ RP RQ)
    then show ?case by(blast dest: bisimE)
  qed
  then show ?thesis
    by(metis bisimTransitive bisimParNil bisimSymmetric bisimParComm)
qed

end

end