Library Semantics

Require Export Syntax.

labels, agents


Inductive label : Set :=
| out : name label
| inp : name label
| tau : label
.

Definition fn_lab (l:label) :=
  match l with
  | tau\{}
  | out a\{a}
  | inp a\{a}
  end.

Definition down_lab (l:label) :=
  match l with
  | tautau
  | out aout (a-1)
  | inp ainp (a-1)
  end.

Inductive abs : Set :=
| abs_def : proc1 abs
.

Definition asubst (F : abs) (P : proc0) : proc0 :=
  match F with
  | abs_def Qsubst Q P
  end.

Inductive conc : Set :=
| conc_def : nat proc0 proc0 conc
.

Inductive agent :=
| ag_proc : proc0 agent
| ag_abs : abs agent
| ag_conc : conc agent
.

Coercion ag_abs : abs >-> agent.
Coercion ag_conc : conc >-> agent.

Tactic Notation "destructA" constr(A) := destruct A as [|[]|[]].

Definition fn_agent A := match A with
| ag_proc Pfn P
| ag_abs Fmatch F with | abs_def Pfn P end
| ag_conc Cmatch C with | conc_def n P Q
    map (fun kk-n) (filter (fun kleb n k) (fn P \u fn Q)) end
 end.

conc_wf checks that bn P has at least n names
Definition conc_wf C := match C with
| conc_def n P Q k, k < n k \in fn P
end.

Definition fmapN f F :=
  match F with | abs_def Pabs_def (mapN f P) end.

Definition cmapN f C :=
  match C with | conc_def n P Qconc_def n (mapN (liftN f n) P)(mapN (liftN f n) Q) end.

Definition amapN f A := match A with
| ag_proc Pag_proc (mapN f P)
| ag_abs FfmapN f F
| ag_conc CcmapN f C
end.


LTS


Definition conc_parl C P : conc :=
  match C with
  | conc_def k P' Qconc_def k P' (Q // (shiftN k P))
  end.

Definition conc_parr P C : conc :=
  match C with
  | conc_def k P' Qconc_def k P' ((shiftN k P) // Q)
  end.

Definition abs_parl F P : abs :=
  match F with
  | abs_def Qabs_def (Q // (shiftV P))
  end.

Definition abs_parr P F : abs :=
  match F with
  | abs_def Qabs_def ((shiftV P) // Q)
  end.

Definition parl A P : agent :=
  match A with
  | ag_abs Fag_abs (abs_parl F P)
  | ag_proc P'ag_proc (P' // P)
  | ag_conc Cag_conc (conc_parl C P)
  end.

Definition parr P A : agent :=
  match A with
  | ag_abs Fag_abs (abs_parr P F)
  | ag_proc P'ag_proc (P // P')
  | ag_conc Cag_conc (conc_parr P C)
  end.

Definition down k x := If (x k) then x else x-1.

Tactic Notation "simpl_down" := unfold down in *; intros_all; default_simp; intuition.

Tactic Notation "simpl_name" := unfold liftN, down, permut in *; default_simp; intuition.

Definition conc_new (C:conc) : conc :=
  match C with
  | conc_def k P QIf k \in fn P then conc_def (S k) P Q
                                     else conc_def k (mapN (down k) P) (nu (mapN (permut k) Q))
  end.

Definition abs_new (F:abs) : abs :=
  match F with
  | abs_def Pabs_def (nu P)
  end.

Definition new (A: agent) : agent :=
  match A with
  | ag_abs Fag_abs (abs_new F)
  | ag_proc Pag_proc (nu P)
  | ag_conc Cag_conc (conc_new C)
  end.

Fixpoint genNu {V:Set} k (P:proc V) :=
  match k with
  | 0 ⇒ P
  | S k'nu (genNu k' P)
  end.

Lemma nu_genNu {V:Set}: (P:proc V) n, nu (genNu n P) = genNu n (nu P).
Proof.
  induction n; simpl; auto.
  intros; rewrite× <- IHn.
Qed.

Definition fshiftN k F := match F with
  | abs_def Pabs_def (shiftN k P)
  end.

Definition appr F C : proc0 :=
  match C with
  | conc_def k P QgenNu k (asubst (fshiftN k F) P // Q)
  end.

Definition appl C F : proc0 :=
  match C with
  | conc_def k P QgenNu k (Q // asubst (fshiftN k F) P)
  end.

Inductive lts: proc0 label agent Prop :=
| lts_out : a P Q, lts (a !(P) Q) (out a) (ag_conc (conc_def 0 P Q))
| lts_inp : a P, lts (a ? P) (inp a) (ag_abs (abs_def P))
| lts_parl : P Q l A, lts P l A lts (P // Q) l (parl A Q)
| lts_parr : P Q l A, lts P l A lts (Q // P) l (parr Q A)
| lts_new : P l A, 0 \notin fn_lab l lts P l A
    lts (nu P)(down_lab l)(new A)
| lts_taul : P Q a F C, lts P (out a) (ag_conc C)
    lts Q (inp a) (ag_abs F) lts (P // Q) tau (ag_proc (appl C F))
| lts_taur : P Q a F C, lts Q (inp a) (ag_abs F)
    lts P (out a) (ag_conc C) lts (Q // P) tau (ag_proc (appr F C))
.

Hint Constructors lts:hopi.


Basic LTS properties


Lemma lts_parl' : P Q l A A', lts P l A parl A Q = A' lts (P // Q) l A'.
Proof.
  intros; subst; eapply lts_parl; eassumption.
Qed.

Lemma lts_parr' : P Q l A A', lts P l A parr Q A = A' lts (Q // P) l A'.
Proof.
  intros; subst; eapply lts_parr; eassumption.
Qed.

Lemma lts_taul' : P A' Q a F C,
    lts P (out a) (ag_conc C) lts Q (inp a) (ag_abs F)
    ag_proc (appl C F) = A' lts (P // Q) tau A'.
Proof.
  intros. subst. eapply lts_taul; eassumption.
Qed.

Lemma lts_taur' : P A' Q a F C,
    lts P (out a) (ag_conc C) lts Q (inp a) (ag_abs F)
    ag_proc (appr F C) = A' lts (Q // P) tau A'.
Proof.
  intros; subst; eapply lts_taur; eassumption.
Qed.

Lemma lts_new' : P l l' A A', 0 \notin fn_lab l lts P l A
    new A = A' l' = down_lab l lts (nu P) l' A'.
Proof.
  intros; subst; eapply lts_new; eassumption.
Qed.

Hint Resolve lts_parl' lts_parr' lts_taul' lts_taur':hopi.

Lemma lts_tau_proc: P A, lts P tau A P', A = ag_proc P'.
Proof.
  introv Hlts. remember tau as l.
  induction Hlts; try (inverts Heql; eauto); try (destruct l; inverts H1);
    try (destruct IHHlts; try reflexivity; subst; eexists; simpl; reflexivity).
Qed.

Lemma lts_inp_abs : P a A, lts P (inp a) A F, A = ag_abs F.
Proof.
  introv Hlts. remember (inp a) as l. gen a.
  induction Hlts; introv Heql; try (inverts Heql; eauto); try (destruct l; inverts H1);
    try (edestruct IHHlts; try reflexivity; subst; eexists; simpl; auto).
Qed.

Lemma lts_out_conc : P a A, lts P (out a) A C, A = ag_conc C.
Proof.
  intros P a A Hlts. remember (out a) as l. gen a.
  induction Hlts; introv Heql; try (inverts Heql; eauto); try (destruct l; inverts H1);
    try (edestruct IHHlts; try reflexivity; subst; eexists; simpl; auto).
Qed.


Lemma mapN_genNu {V:Set}: n f (P:proc V),
    mapN f (genNu n P) = genNu n (mapN (liftN f n) P).
Proof.
  induction n; intros; simpl; auto.
  - rewrite× liftN_0.
  - rewrite IHn. rewrite× liftN_liftN.
Qed.

Lemma genNu_fold {V:Set} : (P:proc V) k, genNu k (nu P) = genNu (S k) P.
Proof.
   intros; induction k; simpl; auto. rewrite <- nu_genNu. auto.
Qed.

Lemma fn_genNu {V:Set}: (P:proc V) n, fn (genNu n P) [=] map (fun kk-n) (filter (fun kleb n k) (fn P)).
Proof.
  induction n; simpl.
  - asserts_rewrite ((fun kk-0) = fun kk). extens; intros; omega.
    rewrite map_id. rewrite filter_id. fsetdec.
  - split; intros. simplfs; (S(a+ n)); split; try omega. apply IHn in H. simplfs. assert (x = S(a + n)) by omega.
    subst. intuition.
    simplfs. apply IHn. destruct x; intuition. simplfs. (S(a+n)). intuition. simplfs. intuition.
    assert (x = a+n) by omega. rewrite H2 in H0; auto.
Qed.

Hint Rewrite @fn_genNu:fs.

Lemma lts_conc_wf : P l (C:conc), lts P l C conc_wf C.
Proof.
  intros. gen_eq: (ag_conc C) as A. gen C.
  induction H; introv HC; try solve [inverts HC].
  - inverts HC. intros_all; omega.
  - destructA A; inverts HC. intros_all. forwards*: IHlts.
  - destructA A; inverts HC. intros_all. forwards*: IHlts.
  - destructA A; inverts HC. forwards:IHlts. reflexivity.
    case_if; intros_all.
    destruct (classic (k = n)); try (subst; auto).
    forwards*: H1 k. omega.
    forwards*: H1 k. rewrite fn_mapN. apply map_spec. k; intuition. simpl_down.
Qed.

Lemma mapN_concwf : f C, conc_wf C conc_wf (cmapN f C).
Proof.
  split; intros; destruct C as [n P Q]; intros_all.
  - forwards*: H. simplfs. k; intuition. simpl_liftN.
  - forwards*: H. simplfs. simpl_liftN.
Qed.

Lemma mapN_eq_on_fn {V:Set} : (P:proc V) f g,
  ( k, k \in fn P f k = g k) mapN f P = mapN g P.
Proof.
  induction P; intros; try solve [simpl; auto].
  - simpl. fequals. apply H. simpl; fsetdec. apply IHP. intros. apply H. simpl; fsetdec.
  - simpl. fequals. apply H. simpl; fsetdec. apply IHP1. intros. apply H. simpl; fsetdec.
    apply IHP2. intros. apply H. simpl; fsetdec.
  - simpl. fequals. apply IHP1. intros. apply H. simpl; fsetdec.
    apply IHP2. intros. apply H. simpl; fsetdec.
  - simpl. erewrite IHP; eauto. intros. unfold liftN.
    case_if; auto. rewrite H; auto. simpl. rewrite downfs_0_spec.
    replace (S (k -1)) with k by omega. auto.
Qed.

Lemma mapN_eq_on_fn_rev {V:Set} : (P:proc V) f g, mapN g P = mapN f P
         n, n \in fn P g n = f n.
Proof.
  induction P; simpl; intros; try fsetdec.
  - simplfs. destruct H0. rewrite singleton_iff in H0. subst. inverts H. auto.
    forwards*: IHP f g. inverts H. auto.
  - simplfs. destruct H0. rewrite singleton_iff in H0. subst. inverts H; auto.
    destruct H0; [forwards*: IHP1 f g | forwards*: IHP2 f g]; inverts H; auto.
  - simplfs. destruct H0; [forwards*: IHP1 f g | forwards*: IHP2 f g]; inverts H; auto.
  - forwards*: IHP (liftN f 1)(liftN g 1)(S n). inverts H; auto. simplfs.
    simpl_liftN. rewrite <- minus_n_O in H. auto.
Qed.

Lemma amapN_amapN : f g A, amapN f (amapN g A) = amapN (fun xf (g x)) A.
Proof.
  intros; destructA A; simpl; rewrite mapN_mapN; auto.
    rewrite mapN_mapN; repeat fequals; extens; intros; simpl_liftN;
    replace (n + g (x1 - n) - n) with (g(x1-n)) by omega; auto.
Qed.

Lemma amapN_id : A, amapN (fun xx) A = A.
Proof.
  intros; destructA A; simpl; try (rewrite mapN_id'; auto).
   asserts_rewrite (liftN (fun x : natx) n = fun xx). extens; simpl_liftN.
   repeat (rewrite mapN_id'); auto.
Qed.

Lemma amapN_eq_on_fn : A f g,
  ( k, k \in fn_agent A f k = g k) amapN f A = amapN g A.
Proof.
  intros; destructA A; simpl in ×.
  - fequals; apply mapN_eq_on_fn; auto.
  - do 2 fequals; apply mapN_eq_on_fn; auto.
  - do 2 fequals; apply mapN_eq_on_fn; intros; simpl_liftN; rewrite H; auto; simplfs; k; intuition;
     simplfs; intuition.
Qed.


LTS and fn


Lemma fn_agent_amapN : A (f : nat nat), fn_agent (amapN f A) [=] map f (fn_agent A).
Proof.
  intros; destructA A; simpl; try solve [rewrite× @fn_mapN; fsetdec].
  split; intros.
  - simplfs. destruct H0; simplfs;
    (simpl_liftN; try solve [omega]; (x0 -n); split; try omega; apply map_spec; x0; split; auto; simplfs; intuition).
  - simplfs. subst.
     (f (x0-n) + n). split; try omega. apply filter_iff; simplfs; auto with hopi. split; try omega.
    destruct H1; [ left | right ]; x0; split; simpl_liftN.
Qed.

Lemma amapN_subset : f A A', fn_agent A \c fn_agent A' fn_agent (amapN f A) \c fn_agent (amapN f A').
Proof.
  intros. do 2 rewrite fn_agent_amapN. apply× map_subset.
Qed.

Lemma fn_agent_new : A, fn_agent (new A) [=] downfs (fn_agent A \- \{0}).
Proof.
  intros; destructA A; simpl; try fsetdec.
  case_if.
  - split; intros.
    × simplfs. x. destruct H0; split; try omega; simplfs; intuition.
    × simplfs. x. destruct H0; split; try omega; simplfs; intuition.
  - split; intros.
    × simplfs. (S x). split; try omega. destruct H0. simplfs. intuition.
        left. simpl_down. subst. assert (x0=n) by omega. subst. fsetdec.
        subst. replace (S (x0 -1)) with x0 by omega. auto.
        simpl in H0. simplfs. intuition. simpl_permut.
    × simplfs. (x-1). split; try omega. simplfs. destruct H0; intuition.
        left. x; simpl_down; intuition.
        right. simpl. simplfs. x; simpl_permut. intuition.
Qed.

Lemma fn_appr_appl : F C, fn (appr F C) [=] fn (appl C F).
Proof.
  intros. destruct F as []; destruct C as [].
    split; simpl; do 2 rewrite fn_genNu; simpl; apply map_subset; apply filter_subset; fsetdec.
Qed.

Lemma fn_C_par {V:Set}: (n:nat) E (Q:proc V), map (fun k : natk - n)
    (filter (fun k : natn <=? k) (E \u fn ((shiftN n) Q)))
    [=] map (fun k : natk - n)
      (filter (fun k : natn <=? k) E) \u fn Q.
Proof.
  intros_all. simplfs; intuition.
  - destruct_hyps. simplfs. intuition. left. x. intuition. simplfs.
    destruct_hyps. assert (x0=a) by omega. substs. intuition.
  - destruct_hyps. simplfs. x. intuition. simplfs.
  - (n+a). intuition. simplfs. intuition. right. a; intuition.
Qed.

Lemma fn_appr_subset : F C, fn (appr F C) \c fn_agent C \u fn_agent F.
Proof.
  intros. destruct F as []; destruct C as [].
    simpl; simplfs; intuition.
    apply subset_trans with (map (fun k : natk - n)
      (filter (fun k : natn <=? k) (((fn p0 \u fn p1) \u fn((shiftN n) p))))).
    apply map_subset. apply filter_subset. simpl. eapply subset_trans. apply union_s_m. apply fn_subst.
    apply Subset_refl. fsetdec. rewrite fn_C_par. fsetdec.
Qed.

Lemma fn_parl: A P, fn_agent (parl A P) [=] fn_agent A \u fn P.
Proof.
  intros. destructA A; simpl. fsetdec. simplfs. fsetdec.
  asserts_rewrite ((filter (fun k : natn <=? k)(fn p \u fn p0 \u fn ((shiftN n) P))) [=] filter (fun k : natn <=? k)
      ((fn p \u fn p0) \u fn ((shiftN n) P))). apply IndexSetProperties.Dec.F.filter_equal; auto with fs. fsetdec.
  rewrite fn_C_par. fsetdec.
Qed.

Lemma fn_parr: A P, fn_agent (parr P A) [=] fn_agent A \u fn P.
Proof.
  intros. destructA A; simpl. fsetdec. simplfs. fsetdec.
  asserts_rewrite ((filter (fun k : natn <=? k)(fn p \u fn ((shiftN n) P) \u fn p0)) [=] filter (fun k : natn <=? k)
      ((fn p \u fn p0) \u fn ((shiftN n) P))). apply IndexSetProperties.Dec.F.filter_equal; auto with fs. fsetdec.
  rewrite fn_C_par. fsetdec.
Qed.

Lemma lts_fn : P l A, lts P l A fn_agent A \c fn P.
Proof.
  intros. induction H; simpl in *; try fsetdec.
  - asserts_rewrite ((fun kk-0) = fun kk). extens; intros; omega.
    rewrite map_id. rewrite filter_id. fsetdec.
  - rewrite fn_parl; fsetdec.
  - rewrite fn_parr; fsetdec.
  - rewrite fn_agent_new. intros_all. simplfs.
  - eapply subset_trans. rewrite <- fn_appr_appl. apply fn_appr_subset. fsetdec.
  - eapply subset_trans. apply fn_appr_subset. fsetdec.
Qed.


The LTS is stable by renaming


Definition lmapN f l :=
  match l with
  | out nout (f n)
  | inp ninp (f n)
  | _l
  end.

Lemma amapN_new : f A, amapN f (new A) = new (amapN (liftN f 1) A).
Proof.
  intros; destructA A; simpl; auto.
  repeat (case_if; simpl).
  + repeat (rewrite mapN_mapN). repeat (rewrite liftN_liftN). auto.
  + false. repeat (rewrite liftN_liftN in *). simpl_liftN. apply C0. simplfs.
     n. intuition; case_if; omega.
  + false. repeat (rewrite liftN_liftN in *). simpl_liftN. apply C. simplfs.
    intuition; case_if; omega.
  + repeat (rewrite mapN_mapN). repeat (rewrite liftN_liftN in *). do 2 fequals. apply mapN_eq_on_fn. intros.
    simpl_name. assert (k=n) by omega. substs. fsetdec. replace (k-1-n) with (k-S n) by omega. omega.
    repeat fequals. extens. intros; simpl_name. replace (x1 - (n + 1)) with (x1 - S n) by omega. omega.
Qed.

Lemma shiftN_mapN {V:Set} : (P:proc V) f n, (shiftN n)(mapN f P) = mapN (liftN f n) (shiftN n P).
Proof.
   intros. repeat (rewrite mapN_mapN).
   apply mapN_eq_on_fn.
   intros. simpl_liftN. replace (n+k-n) with k by omega. auto.
Qed.

Lemma mapN_appl : f F C, appl (cmapN f C) (fmapN f F) = mapN f (appl C F).
Proof.
   intros. destruct F; subst. destruct C; simpl.
   rewrite mapN_genNu. simpl.
   replace (subst ((shiftN n) (mapN f p)) (mapN (liftN f n) p0))
            with (mapN (liftN f n) (subst ((shiftN n) p) p0)); auto.
   simpl. rewrite subst_mapN. rewrite shiftN_mapN. auto.
Qed.

Lemma mapN_appr : f F C, appr (fmapN f F) (cmapN f C) = mapN f (appr F C).
Proof.
  intros. destruct F; subst. destruct C; simpl.
  rewrite mapN_genNu. simpl.
  replace (subst ((shiftN n) (mapN f p)) (mapN (liftN f n) p0))
            with (mapN (liftN f n) (subst ((shiftN n) p) p0)); auto.
  simpl. rewrite subst_mapN. rewrite shiftN_mapN. auto.
Qed.

Lemma amapN_parl: f A P, parl (amapN f A) (mapN f P) = amapN f (parl A P).
Proof.
 intros; destructA A; auto; simpl.
 - rewrite× @mapV_mapN.
 - rewrite× @shiftN_mapN.
Qed.

Lemma amapN_parr: f A P, parr (mapN f P) (amapN f A) = amapN f (parr P A).
Proof.
 intros; destructA A; auto; simpl.
 - rewrite× @mapV_mapN.
 - rewrite× @shiftN_mapN.
Qed.

Lemma mapN_lts : P l A f, lts P l A lts (mapN f P) (lmapN f l) (amapN f A).
Proof.
  introv Hlts. gen f.
  induction Hlts; intros f; simpl; eauto with hopi.
  - rewrite liftN_0. auto with hopi.
  - eapply lts_parl'; eauto. destructA A; simpl; auto.
    rewrite× @mapV_mapN. do 2 rewrite mapN_mapN. repeat fequals. extens. simpl_liftN.
    replace (n+x1-n) with x1 by omega. omega.
  - eapply lts_parr'; eauto. destructA A; simpl; auto.
    rewrite× @mapV_mapN. do 2 rewrite mapN_mapN. repeat fequals. extens. simpl_liftN.
    replace (n+x1-n) with x1 by omega. omega.
  - rewrite amapN_new. forwards: IHHlts (liftN f 1).
    eapply lts_new'; auto; destruct l; simpl_liftN; destruct n; try omega; rewrite singleton_iff in *; omega.
  - eapply lts_taul'; eauto. rewrite× mapN_appl.
  - eapply lts_taur'; eauto. rewrite× mapN_appr.
Qed.

Lemma mapN_lts_rev : P l A f, lts (mapN f P) l A
    injective f ( A' l', A = amapN f A' lts P l' A' l = lmapN f l').
Proof.
  introv Hlts. remember (mapN f P) as P'. gen P f.
  induction Hlts; introv Hp' Hf; destruct P0; inverts Hp'.
  - (ag_conc (conc_def 0 P0_1 P0_2)) (out n).
    intuition; eauto. simpl. rewrite liftN_0. auto.
  - (ag_abs (abs_def P0)). eauto with hopi.
  - edestruct IHHlts as [A' [ l' [HA' [ HltsP Hl'] ]]]; eauto.
     (parl A' P0_2) l'. subst. split; auto with hopi. rewrite× amapN_parl.
  - edestruct IHHlts as [A' [ l' [HA' [ HltsP Hl'] ]]]; eauto.
     (parr P0_1 A') l'. subst. split; auto with hopi. rewrite× amapN_parr.
  -
    destruct (IHHlts _ _ eq_refl (liftN_preserves_injectivity f Hf 1)) as [A' [ l'0 [HA' [ HltsP Hl']]]].
    subst. (new A'). eexists; splits; [ rewrite× amapN_new | apply (lts_new _ l'0) | ];
    destruct l'0; simpl; try fsetdec; simpl_liftN; rewrite singleton_iff in *; omega.
  - edestruct IHHlts2 as [Ain [ lin [HAin [ HltsP2 Hlin] ]]]; eauto with hopi.
    destruct Ain; inverts HAin. destruct lin; inverts Hlin.
    edestruct IHHlts1 as [Aout [ lout [HAout [ HltsP1 Hlout] ]]]; eauto.
    destruct Aout; inverts HAout. destruct lout; inverts Hlout.
    apply Hf in H0; subst.
     (ag_proc (appl c a0)) tau. split; eauto with hopi. rewrite× mapN_appl.
  - edestruct IHHlts2 as [Ain [ lin [HAin [ HltsP2 Hlin] ]]]; eauto.
    destruct Ain; inverts HAin. destruct lin; inverts Hlin.
    edestruct IHHlts1 as [Aout [ lout [HAout [ HltsP1 Hlout] ]]]; eauto.
    destruct Aout; inverts HAout. destruct lout; inverts Hlout.
    apply Hf in H0; subst.
     (ag_proc (appr a c)) tau. split; eauto with hopi. rewrite× mapN_appr.
Qed.