Module Parallelizability


Parallel Semantics of Abstract Basic Blocks and parallelizability test.

Require Setoid.
Require Export AbstractBasicBlocksDef.

Require Import List.
Import ListNotations.
Local Open Scope list_scope.

Require Import Sorting.Permutation.
Require Import Bool.
Local Open Scope lazy_bool_scope.

Definition of the parallel semantics

Module ParallelSemantics (L: SeqLanguage).

Export L.
Local Open Scope list.

Section PARALLEL.
Variable ge: genv.

Fixpoint inst_prun (i: inst) (m tmp old: mem): option mem :=
  match i with
  | nil => Some m
  | (x, e)::i' =>
     match exp_eval ge e tmp old with
     | Some v' => inst_prun i' (assign m x v') (assign tmp x v') old
     | None => None
     end
  end.

Lemma inst_run_prun i: forall m old,
  inst_run ge i m old = inst_prun i m m old.
Proof.
  induction i as [|[y e] i']; cbn; auto.
  intros m old; destruct (exp_eval ge e m old); cbn; auto.
Qed.


Fixpoint prun_iw (p: bblock) m old: option mem :=
  match p with
  | nil => Some m
  | i::p' =>
    match inst_prun i m old old with
    | Some m1 => prun_iw p' m1 old
    | None => None
    end
  end.

Definition prun (p: bblock) m (om: option mem) := exists p', res_eq om (prun_iw p' m m) /\ Permutation p p'.



Lemma inst_prun_equiv i old: forall m1 m2 tmp,
  (forall x, m1 x = m2 x) ->
  res_eq (inst_prun i m1 tmp old) (inst_prun i m2 tmp old).
Proof.
  induction i as [|[x e] i']; cbn; eauto.
  intros m1 m2 tmp H; destruct (exp_eval ge e tmp old); cbn; auto.
  eapply IHi'; unfold assign. intros; destruct (R.eq_dec x x0); auto.
Qed.

Lemma prun_iw_equiv p: forall m1 m2 old,
  (forall x, m1 x = m2 x) ->
  res_eq (prun_iw p m1 old) (prun_iw p m2 old).
Proof.
  induction p as [|i p']; cbn; eauto.
  - intros m1 m2 old H.
    generalize (inst_prun_equiv i old m1 m2 old H);
    destruct (inst_prun i m1 old old); cbn.
    + intros (m3 & H3 & H4); rewrite H3; cbn; eauto.
    + intros H1; rewrite H1; cbn; auto.
Qed.


Lemma prun_iw_app p1: forall m1 old p2,
   prun_iw (p1++p2) m1 old =
     match prun_iw p1 m1 old with
     | Some m2 => prun_iw p2 m2 old
     | None => None
     end.
Proof.
   induction p1; cbn; try congruence.
   intros; destruct (inst_prun _ _ _); cbn; auto.
Qed.

Lemma prun_iw_app_None p1: forall m1 old p2,
   prun_iw p1 m1 old = None ->
   prun_iw (p1++p2) m1 old = None.
Proof.
   intros m1 old p2 H; rewrite prun_iw_app. rewrite H; auto.
Qed.

Lemma prun_iw_app_Some p1: forall m1 old m2 p2,
   prun_iw p1 m1 old = Some m2 ->
   prun_iw (p1++p2) m1 old = prun_iw p2 m2 old.
Proof.
   intros m1 old m2 p2 H; rewrite prun_iw_app. rewrite H; auto.
Qed.

End PARALLEL.
End ParallelSemantics.



Fixpoint notIn {A} (x: A) (l:list A): Prop :=
  match l with
  | nil => True
  | a::l' => x <> a /\ notIn x l'
  end.

Lemma notIn_iff A (x:A) l: (~List.In x l) <-> notIn x l.
Proof.
  induction l; cbn; intuition.
Qed.

Lemma notIn_app A (x:A) l1: forall l2, notIn x (l1++l2) <-> (notIn x l1 /\ notIn x l2).
Proof.
  induction l1; cbn.
  - intuition.
  - intros; rewrite IHl1. intuition.
Qed.


Lemma In_Permutation A (l1 l2: list A): Permutation l1 l2 -> forall x, In x l1 -> In x l2.
Proof.
  induction 1; cbn; intuition.
Qed.

Lemma Permutation_incl A (l1 l2: list A): Permutation l1 l2 -> incl l1 l2.
Proof.
  unfold incl; intros; eapply In_Permutation; eauto.
Qed.

Lemma notIn_incl A (l1 l2: list A) x: incl l1 l2 -> notIn x l2 -> notIn x l1.
Proof.
  unfold incl; rewrite <- ! notIn_iff; intuition.
Qed.


Definition disjoint {A: Type} (l l':list A) : Prop := forall x, In x l -> notIn x l'.

Lemma disjoint_sym_imp A (l1 l2: list A): disjoint l1 l2 -> disjoint l2 l1.
Proof.
  unfold disjoint. intros H x H1. generalize (H x). rewrite <- !notIn_iff. intuition.
Qed.

Lemma disjoint_sym A (l1 l2: list A): disjoint l1 l2 <-> disjoint l2 l1.
Proof.
  constructor 1; apply disjoint_sym_imp; auto.
Qed.


Lemma disjoint_cons_l A (x:A) (l1 l2: list A): disjoint (x::l1) l2 <-> (notIn x l2) /\ (disjoint l1 l2).
Proof.
  unfold disjoint. cbn; intuition subst; auto.
Qed.

Lemma disjoint_cons_r A (x:A) (l1 l2: list A): disjoint l1 (x::l2) <-> (notIn x l1) /\ (disjoint l1 l2).
Proof.
  rewrite disjoint_sym, disjoint_cons_l, disjoint_sym; intuition.
Qed.

Lemma disjoint_app_r A (l l1 l2: list A): disjoint l (l1++l2) <-> (disjoint l l1 /\ disjoint l l2).
Proof.
  unfold disjoint. intuition.
  - generalize (H x H0). rewrite notIn_app; intuition.
  - generalize (H x H0). rewrite notIn_app; intuition.
  - rewrite notIn_app; intuition.
Qed.

Lemma disjoint_app_l A (l l1 l2: list A): disjoint (l1++l2) l <-> (disjoint l1 l /\ disjoint l2 l).
Proof.
  rewrite disjoint_sym, disjoint_app_r; intuition; rewrite disjoint_sym; auto.
Qed.

Lemma disjoint_incl_r A (l1 l2: list A): incl l1 l2 -> forall l, disjoint l l2 -> disjoint l l1.
Proof.
  unfold disjoint. intros; eapply notIn_incl; eauto.
Qed.

Lemma disjoint_incl_l A (l1 l2: list A): incl l1 l2 -> forall l, disjoint l2 l -> disjoint l1 l.
Proof.
  intros; rewrite disjoint_sym. eapply disjoint_incl_r; eauto. rewrite disjoint_sym; auto.
Qed.


Module ParallelizablityChecking (L: SeqLanguage).

Include ParallelSemantics L.

Section PARALLELI.
Variable ge: genv.

Preliminary notions on frames


Lemma notIn_dec (x: R.t) l : { notIn x l } + { In x l }.
Proof.
  destruct (In_dec R.eq_dec x l). constructor 2; auto.
  constructor 1; rewrite <- notIn_iff. auto.
Qed.

Fixpoint frame_assign m1 (f: list R.t) m2 :=
  match f with
  | nil => m1
  | x::f' => frame_assign (assign m1 x (m2 x)) f' m2
  end.

Lemma frame_assign_def f: forall m1 m2 x,
   frame_assign m1 f m2 x = if notIn_dec x f then m1 x else m2 x.
Proof.
  induction f as [|y f] ; cbn; auto.
  - intros; destruct (notIn_dec x []); cbn in *; tauto.
  - intros; rewrite IHf; destruct (notIn_dec x (y::f)); cbn in *.
    + destruct (notIn_dec x f); cbn in *; intuition.
      rewrite assign_diff; auto.
      rewrite <- notIn_iff in *; intuition.
    + destruct (notIn_dec x f); cbn in *; intuition subst.
      rewrite assign_eq; auto.
      rewrite <- notIn_iff in *; intuition.
Qed.

Lemma frame_assign_In m1 f m2 x:
   In x f -> frame_assign m1 f m2 x = m2 x.
Proof.
  intros; rewrite frame_assign_def; destruct (notIn_dec x f); auto.
  rewrite <- notIn_iff in *; intuition.
Qed.

Lemma frame_assign_notIn m1 f m2 x:
   notIn x f -> frame_assign m1 f m2 x = m1 x.
Proof.
  intros; rewrite frame_assign_def; destruct (notIn_dec x f); auto.
  rewrite <- notIn_iff in *; intuition.
Qed.

Definition frame_eq (frame: R.t -> Prop) (om1 om2: option mem): Prop :=
  match om1 with
  | Some m1 => exists m2, om2 = Some m2 /\ forall x, (frame x) -> m1 x = m2 x
  | None => om2 = None
  end.

Lemma frame_eq_list_split f1 (f2: R.t -> Prop) om1 om2:
 frame_eq (fun x => In x f1) om1 om2 ->
 (forall m1 m2 x, om1 = Some m1 -> om2 = Some m2 -> f2 x -> notIn x f1 -> m1 x = m2 x) ->
 frame_eq f2 om1 om2.
Proof.
  unfold frame_eq; destruct om1 as [ m1 | ]; cbn; auto.
  intros (m2 & H0 & H1); subst.
  intros H.
  eexists; intuition eauto.
  destruct (notIn_dec x f1); auto.
Qed.


Writing frames


Fixpoint inst_wframe(i:inst): list R.t :=
  match i with
  | nil => nil
  | a::i' => (fst a)::(inst_wframe i')
  end.

Lemma inst_wframe_correct i m' old: forall m tmp,
  inst_prun ge i m tmp old = Some m' ->
  forall x, notIn x (inst_wframe i) -> m' x = m x.
Proof.
  induction i as [|[y e] i']; cbn.
  - intros m tmp H x H0; inversion_clear H; auto.
  - intros m tmp H x (H1 & H2); destruct (exp_eval ge e tmp old); cbn; try congruence.
    replace (m x) with (assign m y v x); eauto.
    rewrite assign_diff; auto.
Qed.

Lemma inst_prun_fequiv i old: forall m1 m2 tmp,
  frame_eq (fun x => In x (inst_wframe i)) (inst_prun ge i m1 tmp old) (inst_prun ge i m2 tmp old).
Proof.
  induction i as [|[y e] i']; cbn.
  - intros m1 m2 tmp; eexists; intuition eauto.
  - intros m1 m2 tmp. destruct (exp_eval ge e tmp old); cbn; auto.
    eapply frame_eq_list_split; eauto. clear IHi'.
    intros m1' m2' x H1 H2.
    lapply (inst_wframe_correct i' m1' old (assign m1 y v) (assign tmp y v)); eauto.
    lapply (inst_wframe_correct i' m2' old (assign m2 y v) (assign tmp y v)); eauto.
    intros Xm2 Xm1 H H0. destruct H.
    + subst. rewrite Xm1, Xm2; auto. rewrite !assign_eq. auto.
    + rewrite <- notIn_iff in H0; tauto.
Qed.

Lemma inst_prun_None i m1 m2 tmp old:
  inst_prun ge i m1 tmp old = None ->
  inst_prun ge i m2 tmp old = None.
Proof.
  intros H; generalize (inst_prun_fequiv i old m1 m2 tmp).
  rewrite H; cbn; auto.
Qed.

Lemma inst_prun_Some i m1 m2 tmp old m1':
  inst_prun ge i m1 tmp old = Some m1' ->
  res_eq (Some (frame_assign m2 (inst_wframe i) m1')) (inst_prun ge i m2 tmp old).
Proof.
  intros H; generalize (inst_prun_fequiv i old m1 m2 tmp).
  rewrite H; cbn.
  intros (m2' & H1 & H2).
  eexists; intuition eauto.
  rewrite frame_assign_def.
  lapply (inst_wframe_correct i m2' old m2 tmp); eauto.
  destruct (notIn_dec x (inst_wframe i)); auto.
  intros X; rewrite X; auto.
Qed.

Fixpoint bblock_wframe(p:bblock): list R.t :=
  match p with
  | nil => nil
  | i::p' => (inst_wframe i)++(bblock_wframe p')
  end.

Local Hint Resolve Permutation_app_head Permutation_app_tail Permutation_app_comm: core.

Lemma bblock_wframe_Permutation p p':
 Permutation p p' -> Permutation (bblock_wframe p) (bblock_wframe p').
Proof.
  induction 1 as [|i p p'|i1 i2 p|p1 p2 p3]; cbn; auto.
  - rewrite! app_assoc; auto.
  - eapply Permutation_trans; eauto.
Qed.


Checking that parallel semantics is deterministic


Fixpoint is_det (p: bblock): Prop :=
  match p with
  | nil => True
  | i::p' =>
       disjoint (inst_wframe i) (bblock_wframe p')
    /\ is_det p'
  end.

Lemma is_det_Permutation p p':
 Permutation p p' -> is_det p -> is_det p'.
Proof.
  induction 1; cbn; auto.
  - intros; intuition. eapply disjoint_incl_r. 2: eauto.
    eapply Permutation_incl. eapply Permutation_sym.
    eapply bblock_wframe_Permutation; auto.
  - rewrite! disjoint_app_r in * |- *. intuition.
    rewrite disjoint_sym; auto.
Qed.

Theorem is_det_correct p p':
  Permutation p p' ->
  is_det p ->
  forall m old, res_eq (prun_iw ge p m old) (prun_iw ge p' m old).
Proof.
  induction 1 as [ | i p p' | i1 i2 p | p1 p2 p3 ]; cbn; eauto.
  - intros [H0 H1] m old.
    remember (inst_prun ge i m old old) as om0.
    destruct om0 as [ m0 | ]; cbn; auto.
  - rewrite disjoint_app_r.
    intros ([Z1 Z2] & Z3 & Z4) m old.
    remember (inst_prun ge i2 m old old) as om2.
    destruct om2 as [ m2 | ]; cbn; auto.
    + remember (inst_prun ge i1 m old old) as om1.
      destruct om1 as [ m1 | ]; cbn; auto.
      * lapply (inst_prun_Some i2 m m1 old old m2); cbn; auto.
        lapply (inst_prun_Some i1 m m2 old old m1); cbn; auto.
        intros (m1' & Hm1' & Xm1') (m2' & Hm2' & Xm2').
        rewrite Hm1', Hm2'; cbn.
        eapply prun_iw_equiv.
        intros x; rewrite <- Xm1', <- Xm2'. clear Xm2' Xm1' Hm1' Hm2' m1' m2'.
        rewrite frame_assign_def.
        rewrite disjoint_sym in Z1; unfold disjoint in Z1.
        destruct (notIn_dec x (inst_wframe i1)) as [ X1 | X1 ].
        { rewrite frame_assign_def; destruct (notIn_dec x (inst_wframe i2)) as [ X2 | X2 ]; auto.
          erewrite (inst_wframe_correct i2 m2 old m old); eauto.
          erewrite (inst_wframe_correct i1 m1 old m old); eauto.
        }
        rewrite frame_assign_notIn; auto.
     * erewrite inst_prun_None; eauto. cbn; auto.
   + remember (inst_prun ge i1 m old old) as om1.
     destruct om1 as [ m1 | ]; cbn; auto.
     erewrite inst_prun_None; eauto.
  - intros; eapply res_eq_trans.
    eapply IHPermutation1; eauto.
    eapply IHPermutation2; eauto.
    eapply is_det_Permutation; eauto.
Qed.

Standard Frames


Fixpoint exp_frame (e: exp): list R.t :=
  match e with
  | PReg x => x::nil
  | Op o le => list_exp_frame le
  | Old e => exp_frame e
  end
with list_exp_frame (le: list_exp): list R.t :=
  match le with
  | Enil => nil
  | Econs e le' => exp_frame e ++ list_exp_frame le'
  | LOld le => list_exp_frame le
  end.

Lemma exp_frame_correct e old1 old2:
  (forall x, In x (exp_frame e) -> old1 x = old2 x) ->
  forall m1 m2, (forall x, In x (exp_frame e) -> m1 x = m2 x) ->
   (exp_eval ge e m1 old1)=(exp_eval ge e m2 old2).
Proof.
  induction e using exp_mut with (P0:=fun l => (forall x, In x (list_exp_frame l) -> old1 x = old2 x) -> forall m1 m2, (forall x, In x (list_exp_frame l) -> m1 x = m2 x) ->
   (list_exp_eval ge l m1 old1)=(list_exp_eval ge l m2 old2)); cbn; auto.
  - intros H1 m1 m2 H2; rewrite H2; auto.
  - intros H1 m1 m2 H2; erewrite IHe; eauto.
  - intros H1 m1 m2 H2; erewrite IHe, IHe0; eauto;
    intros; (eapply H1 || eapply H2); rewrite in_app_iff; auto.
Qed.

Fixpoint inst_frame (i: inst): list R.t :=
  match i with
  | nil => nil
  | a::i' => (fst a)::(exp_frame (snd a) ++ inst_frame i')
  end.

Lemma inst_wframe_frame i x: In x (inst_wframe i) -> In x (inst_frame i).
Proof.
  induction i as [ | [y e] i']; cbn; intuition.
Qed.


Lemma inst_frame_correct i wframe old1 old2: forall m tmp1 tmp2,
  (disjoint (inst_frame i) wframe) ->
  (forall x, notIn x wframe -> old1 x = old2 x) ->
  (forall x, notIn x wframe -> tmp1 x = tmp2 x) ->
  inst_prun ge i m tmp1 old1 = inst_prun ge i m tmp2 old2.
Proof.
  induction i as [|[x e] i']; cbn; auto.
  intros m tmp1 tmp2; rewrite disjoint_cons_l, disjoint_app_l.
  intros (H1 & H2 & H3) H6 H7.
  replace (exp_eval ge e tmp1 old1) with (exp_eval ge e tmp2 old2).
  - destruct (exp_eval ge e tmp2 old2); auto.
    eapply IHi'; eauto.
    cbn; intros x0 H0; unfold assign. destruct (R.eq_dec x x0); cbn; auto.
  - unfold disjoint in H2; apply exp_frame_correct.
    intros;rewrite H6; auto.
    intros;rewrite H7; auto.
Qed.

Parallelizability


Fixpoint pararec (p: bblock) (wframe: list R.t): Prop :=
  match p with
  | nil => True
  | i::p' =>
       disjoint (inst_frame i) wframe
    /\ pararec p' ((inst_wframe i) ++ wframe)
  end.

Lemma pararec_disjoint (p: bblock): forall wframe, pararec p wframe -> disjoint (bblock_wframe p) wframe.
Proof.
  induction p as [|i p']; cbn.
  - unfold disjoint; cbn; intuition.
  - intros wframe [H0 H1]; rewrite disjoint_app_l.
    generalize (IHp' _ H1).
    rewrite disjoint_app_r. intuition.
    eapply disjoint_incl_l. 2: eapply H0.
    unfold incl. eapply inst_wframe_frame; eauto.
Qed.

Lemma pararec_det p: forall wframe, pararec p wframe -> is_det p.
Proof.
  induction p as [|i p']; cbn; auto.
  intros wframe [H0 H1]. generalize (pararec_disjoint _ _ H1). rewrite disjoint_app_r.
  intuition.
  - apply disjoint_sym; auto.
  - eapply IHp'. eauto.
Qed.

Lemma pararec_correct p old: forall wframe m,
  pararec p wframe ->
  (forall x, notIn x wframe -> m x = old x) ->
  run ge p m = prun_iw ge p m old.
Proof.
  elim p; clear p; cbn; auto.
  intros i p' X wframe m [H H0] H1.
  erewrite inst_run_prun, inst_frame_correct; eauto.
  remember (inst_prun ge i m old old) as om0.
  destruct om0 as [m0 | ]; try congruence.
  eapply X; eauto.
  intro x; rewrite notIn_app. intros [H3 H4].
  rewrite <- H1; auto.
  eapply inst_wframe_correct; eauto.
Qed.

Definition parallelizable (p: bblock) := pararec p nil.

Theorem parallelizable_correct p m om':
  parallelizable p -> (prun ge p m om' <-> res_eq om' (run ge p m)).
Proof.
  intros H. constructor 1.
  - intros (p' & H0 & H1). eapply res_eq_trans; eauto.
    erewrite pararec_correct; eauto.
    eapply res_eq_sym.
    eapply is_det_correct; eauto.
    eapply pararec_det; eauto.
  - intros; unfold prun.
    eexists. constructor 1. 2: apply Permutation_refl.
    erewrite pararec_correct in H0; eauto.
Qed.

End PARALLELI.

End ParallelizablityChecking.


We assume a datatype PseudoRegSet.t refining list R.t


This data-refinement is given by an abstract "invariant" match_frame below, preserved by the following operations.

Module Type PseudoRegSet.

Declare Module R: PseudoRegisters.

Parameter t: Type.
Parameter match_frame: t -> (list R.t) -> Prop.

Parameter empty: t.
Parameter empty_match_frame: match_frame empty nil.

Parameter add: R.t -> t -> t.
Parameter add_match_frame: forall s x l, match_frame s l -> match_frame (add x s) (x::l).

Parameter union: t -> t -> t.
Parameter union_match_frame: forall s1 s2 l1 l2, match_frame s1 l1 -> match_frame s2 l2 -> match_frame (union s1 s2) (l1++l2).

Parameter is_disjoint: t -> t -> bool.
Parameter is_disjoint_match_frame: forall s1 s2 l1 l2, match_frame s1 l1 -> match_frame s2 l2 -> (is_disjoint s1 s2)=true -> disjoint l1 l2.

End PseudoRegSet.


Lemma lazy_andb_bool_true (b1 b2: bool): b1 &&& b2 = true <-> b1 = true /\ b2 = true.
Proof.
  destruct b1, b2; intuition.
Qed.




Module ParallelChecks (L: SeqLanguage) (S:PseudoRegSet with Module R:=L.LP.R).

Include ParallelizablityChecking L.

Section PARALLEL2.
Variable ge: genv.

Local Hint Resolve S.empty_match_frame S.add_match_frame S.union_match_frame S.is_disjoint_match_frame: core.

Now, refinement of each operation toward parallelizable

Fixpoint inst_wsframe(i:inst): S.t :=
  match i with
  | nil => S.empty
  | a::i' => S.add (fst a) (inst_wsframe i')
  end.

Lemma inst_wsframe_correct i: S.match_frame (inst_wsframe i) (inst_wframe i).
Proof.
  induction i; cbn; auto.
Qed.

Fixpoint exp_sframe (e: exp): S.t :=
  match e with
  | PReg x => S.add x S.empty
  | Op o le => list_exp_sframe le
  | Old e => exp_sframe e
  end
with list_exp_sframe (le: list_exp): S.t :=
  match le with
  | Enil => S.empty
  | Econs e le' => S.union (exp_sframe e) (list_exp_sframe le')
  | LOld le => list_exp_sframe le
  end.

Lemma exp_sframe_correct e: S.match_frame (exp_sframe e) (exp_frame e).
Proof.
  induction e using exp_mut with (P0:=fun l => S.match_frame (list_exp_sframe l) (list_exp_frame l)); cbn; auto.
Qed.

Fixpoint inst_sframe (i: inst): S.t :=
  match i with
  | nil => S.empty
  | a::i' => S.add (fst a) (S.union (exp_sframe (snd a)) (inst_sframe i'))
  end.

Local Hint Resolve exp_sframe_correct: core.

Lemma inst_sframe_correct i: S.match_frame (inst_sframe i) (inst_frame i).
Proof.
  induction i as [|[y e] i']; cbn; auto.
Qed.

Local Hint Resolve inst_wsframe_correct inst_sframe_correct: core.

Fixpoint is_pararec (p: bblock) (wsframe: S.t): bool :=
  match p with
  | nil => true
  | i::p' =>
       S.is_disjoint (inst_sframe i) wsframe
    &&& is_pararec p' (S.union (inst_wsframe i) wsframe)
  end.

Lemma is_pararec_correct (p: bblock): forall s l, S.match_frame s l -> (is_pararec p s)=true -> (pararec p l).
Proof.
  induction p; cbn; auto.
  intros s l H1 H2; rewrite lazy_andb_bool_true in H2. destruct H2 as [H2 H3].
  constructor 1; eauto.
Qed.

Definition is_parallelizable (p: bblock) := is_pararec p S.empty.

Lemma is_para_correct_aux p: is_parallelizable p = true -> parallelizable p.
Proof.
  unfold is_parallelizable, parallelizable; intros; eapply is_pararec_correct; eauto.
Qed.

Theorem is_parallelizable_correct p:
  is_parallelizable p = true -> forall m om', (prun ge p m om' <-> res_eq om' (run ge p m)).
Proof.
  intros; apply parallelizable_correct.
  apply is_para_correct_aux. auto.
Qed.

End PARALLEL2.
End ParallelChecks.



Implementing the datatype PosPseudoRegSet.t refining list R.t



Require Import PArith.
Require Import MSets.MSetPositive.

Module PosPseudoRegSet <: PseudoRegSet with Module R:=Pos.

Module R:=Pos.


Definition t:=PositiveSet.t.

Definition match_frame (s:t) (l:list R.t): Prop
 := forall x, PositiveSet.In x s <-> In x l.

Definition empty:=PositiveSet.empty.

Lemma empty_match_frame: match_frame empty nil.
Proof.
  unfold match_frame, empty, PositiveSet.In; cbn; intuition.
Qed.

Definition add: R.t -> t -> t := PositiveSet.add.

Lemma add_match_frame: forall s x l, match_frame s l -> match_frame (add x s) (x::l).
Proof.
  unfold match_frame, add; cbn.
  intros s x l H y. rewrite PositiveSet.add_spec, H.
  intuition.
Qed.

Definition union: t -> t -> t := PositiveSet.union.
Lemma union_match_frame: forall s1 s2 l1 l2, match_frame s1 l1 -> match_frame s2 l2 -> match_frame (union s1 s2) (l1++l2).
Proof.
  unfold match_frame, union.
  intros s1 s2 l1 l2 H1 H2 x. rewrite PositiveSet.union_spec, H1, H2.
  intuition.
Qed.

Fixpoint is_disjoint (s s': PositiveSet.t) : bool :=
  match s with
  | PositiveSet.Leaf => true
  | PositiveSet.Node l o r =>
    match s' with
    | PositiveSet.Leaf => true
    | PositiveSet.Node l' o' r' =>
      if (o &&& o') then false else (is_disjoint l l' &&& is_disjoint r r')
    end
  end.

Lemma is_disjoint_spec_true s: forall s', is_disjoint s s' = true -> forall x, PositiveSet.In x s -> PositiveSet.In x s' -> False.
Proof.
  unfold PositiveSet.In; induction s as [ |l IHl o r IHr]; cbn; try discriminate.
  destruct s' as [|l' o' r']; cbn; try discriminate.
  intros X.
  assert (H: ~(o = true /\ o'=true) /\ is_disjoint l l' = true /\ is_disjoint r r'=true).
  { destruct o, o', (is_disjoint l l'), (is_disjoint r r'); cbn in X; intuition. }
  clear X; destruct H as (H & H1 & H2).
  destruct x as [i|i|]; cbn; eauto.
Qed.

Lemma is_disjoint_match_frame: forall s1 s2 l1 l2, match_frame s1 l1 -> match_frame s2 l2 -> (is_disjoint s1 s2)=true -> disjoint l1 l2.
Proof.
  unfold match_frame, disjoint.
  intros s1 s2 l1 l2 H1 H2 H3 x.
  rewrite <- notIn_iff, <- H1, <- H2.
  intros H4 H5; eapply is_disjoint_spec_true; eauto.
Qed.

End PosPseudoRegSet.