Theory Strong_Late_Sim

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

definition derivative :: "pi  pi  subject  name  (pi × pi) set  bool" where
  "derivative P Q a x Rel  case a of InputS b  (u. (P[x::=u], Q[x::=u])  Rel)
                                    | BoundOutputS b  (P, Q)  Rel"

definition simulation :: "pi  (pi × pi) set  pi  bool" ("_ ↝[_] _" [80, 80, 80] 80) where
  "P ↝[Rel] Q  (a x Q'. Q a«x»  Q'  x  P  (P'. P a«x»  P'  derivative P' Q' a x Rel)) 
                 (α Q'. Q α  Q'  (P'. P α  P'  (P', Q')  Rel))"

lemma monotonic: 
  fixes A  :: "(pi × pi) set"
  and   B  :: "(pi × pi) set"
  and   P  :: pi
  and   P' :: pi

  assumes "P ↝[A] P'"
  and     "A  B"

  shows "P ↝[B] P'"
using assms
apply(auto simp add: simulation_def derivative_def)
by(case_tac a) fastforce+

lemma derivativeMonotonic:
  fixes A :: "(pi × pi) set"
  and   B :: "(pi × pi) set"
  and   P :: pi
  and   Q :: pi
  and   a :: subject
  and   x :: name

  assumes "derivative P Q a x A"
  and     "A  B"
  
  shows "derivative P Q a x B"
using assms
by(case_tac a, auto simp add: derivative_def)

lemma derivativeEqvtI:
  fixes P    :: pi
  and   Q    :: pi
  and   a    :: subject
  and   x    :: name
  and   Rel  :: "(pi × pi) set"
  and   perm :: "name prm"

  assumes Der: "derivative P Q a x Rel"
  and     Eqvt: "eqvt Rel"
  
  shows "derivative (perm  P) (perm  Q) (perm  a) (perm  x) Rel"
using assms
apply(case_tac a, auto simp add: derivative_def)
apply(erule_tac x="rev perm  u" in allE)
apply(drule_tac perm=perm in eqvtRelI)
apply(blast)
apply(force simp add: eqvt_subs name_per_rev)
by(force simp add: eqvt_def)

lemma derivativeEqvtI2:
  fixes P    :: pi
  and   Q    :: pi
  and   a    :: subject
  and   x    :: name
  and   Rel  :: "(pi × pi) set"
  and   perm :: "name prm"

  assumes Der: "derivative P Q a x Rel"
  and     Eqvt: "eqvt Rel"
  
  shows "derivative (perm  P) (perm  Q) a (perm  x) Rel"
using assms
apply(case_tac a, auto simp add: derivative_def)
apply(erule_tac x="rev perm  u" in allE)
apply(drule_tac perm=perm in eqvtRelI)
apply(blast)
apply(force simp add: eqvt_subs name_per_rev)
by(force simp add: eqvt_def)

lemma freshUnit[simp]:
  fixes y :: name

  shows "y  ()"
by(auto simp add: fresh_def supp_unit)

lemma simCasesCont[consumes 1, case_names Bound Free]:
  fixes P   :: pi
  and   Q   :: pi
  and   Rel :: "(pi × pi) set"
  and   C   :: "'a::fs_name"

  assumes Eqvt:  "eqvt Rel"
  and     Bound: "a x Q'. Q  a«x»  Q'; x  P; x  Q; x  a; x  C  P'. P  a«x»  P'  derivative P' Q' a x Rel"
  and     Free:  "α Q'. Q  α  Q'  P'. P  α  P'  (P', Q')  Rel"

  shows "P ↝[Rel] Q"
using Free
proof(auto simp add: simulation_def)
  fix a x Q'
  assume "(x::name)  P"
  assume Trans: "Q  a«x»  Q'"
  
  obtain y::name where "y  P" and "y  Q" and "y  a" and "y  C" and "y  Q'" and "y  x"
    by(generate_fresh "name") auto

  from Trans y  Q' have "Q  a«y»  [(x, y)]  Q'" by(simp add: alphaBoundResidual)
  hence "P'. P  a«y»  P'  derivative P' ([(x, y)]  Q') a y Rel" 
    using y  P y  Q y  a y  C
    by(rule Bound)
  then obtain P' where PTrans: "P  a«y»  P'" and PDer: "derivative P' ([(x, y)]  Q') a y Rel"
    by blast
  
  from PTrans x  P y  x have "x  P'" by(force intro: freshBoundDerivative)
  with PTrans have "P  a«x»  [(x, y)]  P'" by(simp add: alphaBoundResidual name_swap)
  moreover have "derivative ([(x, y)]  P') Q' a x Rel"
  proof -
    from PDer Eqvt have "derivative ([(x, y)]  P') ([(x, y)]  [(x, y)]  Q') a ([(x, y)]  y) Rel"
      by(rule derivativeEqvtI2)
    with y  x show ?thesis by(simp add: name_calc)
  qed
  ultimately show "P'. P a«x»  P'  derivative P' Q' a x Rel" by blast
qed

lemma simCases[case_names Bound Free]:
  fixes P   :: pi
  and   Q   :: pi
  and   Rel :: "(pi × pi) set"

  assumes Bound: "a y Q'. Q  a«y»  Q'; y  P  P'. P  a«y»  P'  derivative P' Q' a y Rel"
  and     Free:  "α Q'. Q  α  Q'  P'. P  α  P'  (P', Q')  Rel"

  shows "P ↝[Rel] Q"
using assms
by(auto simp add: simulation_def)

lemma resSimCases[consumes 1, case_names BoundOutput BoundR FreeR]:
  fixes x   :: name
  and   P   :: pi
  and   Rel :: "(pi × pi) set"
  and   Q   :: pi
  and   C   :: "'a::fs_name"

  assumes Eqvt:    "eqvt Rel"
  and     BoundO:  "Q' a. Q a[x]  Q'; a  x  P'. P ax>  P'  (P', Q')  Rel"
  and     BR:      "Q' a y. Q a«y»  Q'; x  a; x  y; y  C  P'. P a«y»  P'  derivative P' (x>Q') a y Rel"
  and     BF:      "Q' α. Q α  Q'; x  α  P'. P α  P'  (P', x>Q')  Rel"

  shows "P ↝[Rel] x>Q"
using Eqvt
proof(induct rule: simCasesCont[where C="(C, x, Q)"])
  case(Bound a y Q')
  have "y  (C, x, Q)" by fact
  hence yFreshC: "y  C" and yineqx: "y  x" and "y  Q"
    by(simp add: fresh_prod)+
  have "x>Q a«y»  Q'" by fact
  thus ?case using yineqx y  Q
  proof(induct rule: resCasesB)
    case(cOpen a' Q')
    have "Q a'[x]  Q'" and "a'  x" by fact+
    then obtain P' where PTrans: "P a'x>  P'" and P'RelQ': "(P', Q')  Rel" by(force dest: BoundO)
    
    from PTrans y  P yineqx have "y  P'" by(force dest: freshBoundDerivative)
    with PTrans have "P a'y>  ([(x, y)]  P')" by(simp add: alphaBoundResidual)
    moreover from P'RelQ' Eqvt have "([(x, y)]  P', [(x, y)]  Q')  Rel" by(auto simp add: eqvt_def)
    ultimately show ?case by(force simp add: derivative_def name_swap) 
  next
    case(cRes Q')
    have "Q a«y»  Q'" and "x  a" by fact+
    with yineqx yFreshC show ?case by(force dest: BR)
  qed
next
  case(Free α Q')
  have "x>Q α  Q'" by fact
  thus ?case
  proof(induct rule: resCasesF)
    case(cRes Q')
    have "Q α  Q'" and "x  α" by fact+
    thus ?case by(rule BF)
  qed
qed

lemma simE:
  fixes P   :: pi
  and   Rel :: "(pi × pi) set"
  and   Q   :: pi
  and   a   :: subject
  and   x   :: name
  and   Q'  :: pi

  assumes "P ↝[Rel] Q"

  shows "Q  a«x»  Q'  x  P  P'. P  a«x»  P'  (derivative P' Q' a x Rel)"
  and   "Q  α  Q'  P'. P  α  P'  (P', Q')  Rel"
using assms by(simp add: simulation_def)+

lemma eqvtI:
  fixes P    :: pi
  and   Q    :: pi
  and   Rel  :: "(pi × pi) set"
  and   perm :: "name prm"

  assumes Sim: "P ↝[Rel] Q"
  and     RelRel': "Rel  Rel'"
  and     EqvtRel': "eqvt Rel'"

  shows "(perm  P) ↝[Rel'] (perm  Q)"
proof(induct rule: simCases)
  case(Bound a y Q')
  have QTrans: "(perm  Q)  a«y»  Q'" and yFreshP: "y  perm  P" by fact+
  
  from QTrans have "(rev perm  (perm  Q))  rev perm  (a«y»  Q')"
    by(rule transitions.eqvt)
  hence "Q  (rev perm  a)«(rev perm  y)»  (rev perm  Q')" 
    by(simp add: name_rev_per)
  moreover from yFreshP have "(rev perm  y)  P" by(simp add: name_fresh_left)
  ultimately have "P'. P  (rev perm  a)«rev perm  y»  P'  derivative P' (rev perm  Q') (rev perm  a) (rev perm  y) Rel" using Sim
    by(force intro: simE)
  then obtain P' where PTrans: "P  (rev perm  a)«rev perm  y»  P'" and Pderivative: "derivative P' (rev perm  Q') (rev perm  a) (rev perm  y) Rel" by blast
  
  from PTrans have "(perm  P)  perm  ((rev perm  a)«rev perm  y»  P')" by(rule transitions.eqvt)
  hence L1: "(perm  P)  a«y»  (perm  P')" by(simp add: name_per_rev)
  from Pderivative RelRel' have "derivative P' (rev perm  Q') (rev perm  a) (rev perm  y) Rel'"
    by(rule derivativeMonotonic)
  hence "derivative (perm  P') (perm  (rev perm  Q')) (perm  (rev perm  a)) (perm  (rev perm  y)) Rel'" using EqvtRel'
    by(rule derivativeEqvtI)
  hence "derivative (perm  P') Q' a y Rel'" by(simp add: name_per_rev)
  with L1 show ?case by blast
next
  case(Free α Q')
  have "(perm  Q)  α  Q'" by fact

  hence "(rev perm  (perm  Q))  rev perm  (α  Q')"
    by(rule transitions.eqvt)
  hence "Q  (rev perm  α)  (rev perm  Q')" 
    by(simp add: name_rev_per)
  with Sim have "P'. P  (rev perm  α)  P'  (P', (rev perm  Q'))  Rel"
    by(force intro: simE)
  then obtain P' where PTrans: "P  (rev perm  α)  P'" and PRel: "(P', (rev perm  Q'))  Rel"
    by blast
    
  from PTrans have "(perm  P)  perm  ((rev perm  α) P')" by(rule transitions.eqvt)
  hence L1: "(perm  P)  α  (perm  P')" by(simp add: name_per_rev)
  from PRel EqvtRel' RelRel'  have "((perm  P'), (perm  (rev perm  Q')))  Rel'"
    by(force intro: eqvtRelI)
  hence "((perm  P'), Q')  Rel'" by(simp add: name_per_rev)
  with L1 show "P'. (perm  P) α  P'  (P', Q')  Rel'" by blast
qed

lemma derivativeReflexive:
  fixes P   :: pi
  and   a   :: subject
  and   x   :: name
  and   Rel :: "(pi × pi) set"
  
  assumes "Id  Rel"

  shows "derivative P P a x Rel"
using assms
apply(cases a)
by(auto simp add: derivative_def)
(*
lemma simActFreeCases[consumes 0, case_names Der]:
  fixes P   :: pi
  and   α   :: freeRes
  and   Q'  :: pi
  and   Rel :: "(pi × pi) set"

  assumes "∃P'. P ⟼α ≺ P' ∧ (P', Q') ∈ Rel"

  shows "simAct P (α ≺ Q') P Rel"
using assms
by(simp add: simAct_def residualInject)
*)
(*****************Reflexivity and transitivity*********************)

lemma reflexive:
  fixes P   :: pi
  and   Rel :: "(pi × pi) set"

  assumes "Id  Rel"

  shows "P ↝[Rel] P"
using assms
by(auto simp add: simulation_def derivativeReflexive)

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

  assumes PSimQ: "P ↝[Rel] Q"
  and     QSimR: "Q ↝[Rel'] R"
  and     Eqvt': "eqvt Rel''"
  and     Trans: "Rel O Rel'  Rel''"

  shows "P ↝[Rel''] R"
using Eqvt'
proof(induct rule: simCasesCont[where C=Q])
  case(Bound a x R')
  have RTrans: "R  a«x»  R'" by fact

  from x  Q QSimR RTrans obtain Q' where QTrans: "Q  a«x»  Q'"
                                        and QDer: "derivative Q' R' a x Rel'" 
    by(blast dest: simE)
  with QTrans x  P PSimQ obtain P' where PTrans: "P  a«x»  P'"
                                        and PDer: "derivative P' Q' a x Rel"
    by(blast dest: simE)
  moreover from PDer QDer Trans have "derivative P' R' a x Rel''"
    by(cases a) (auto simp add: derivative_def)
  ultimately show ?case by blast
next
  case(Free α R')
  have RTrans: "R  α  R'" by fact
  with QSimR obtain Q' where QTrans: "Q  α  Q'" 
                         and Q'RelR': "(Q', R')  Rel'"
    by(blast dest: simE)
  from QTrans PSimQ obtain P' where PTrans: "P  α  P'"
                                and P'RelQ': "(P', Q')  Rel"
    by(blast dest: simE)
  from P'RelQ' Q'RelR' Trans have "(P', R')  Rel''" by blast
  with PTrans show ?case by blast
qed

end