Library Scat.Renaming

Handling of variables (frames, renaming) for conditions


Require Import Coq.FSets.FMapPositive.
Require Import Coq.Structures.OrderedTypeEx.
Require Import PArith.
Require Import PArith.POrderedType.

Require Export Conditions.

We introduce a notion of "frame bound". Hence, tbounds bound t means that all variables of t are lower than bound

Fixpoint tbounds (bound: positive) (t: term): Prop :=
 match t with
 | tvar x ⇒ Zpos (vid x) < Zpos bound
 | tcte c ⇒ True
 | tbin op tl tr ⇒ tbounds bound tl ∧ tbounds bound tr
 | told t ⇒ tbounds bound t
 | tapp f t ⇒ tbounds bound t
 end.

Lemma tbounds_Zle t bound1:
   tbounds bound1 t → ∀ bound2:positive, (Zpos bound1) ≤ (Zpos bound2) → tbounds bound2 t.
Proof.
  induction t; simpl; intuition.
Qed.

Hint Resolve tbounds_Zle: echecker.

frameeq bound1 bound2 s s' means that s and s' coincide on interval bound1 .. bound2-1.

Definition frameeq (bound1: Z) (bound2: positive) (s s': state) : Prop
 := ∀ x, bound1 ≤ (Zpos x) < Zpos bound2 → (s x)=(s' x).
Hint Unfold frameeq: checker.

Lemma frameeq_Zle bound1 bound2 bound3 s s':
  (frameeq bound1 bound3 s s') → Zpos bound2 ≤ Zpos bound3
   → frameeq bound1 bound2 s s'.
Proof.
  unfold frameeq; intuition.
Qed.

Lemma frameeq_sym bound1 bound2 s1 s2:
  (frameeq bound1 bound2 s1 s2) → (frameeq bound1 bound2 s2 s1).
Proof.
  unfold frameeq; intros; symmetry; auto.
Qed.

Lemma frameeq_trans bound1 bound2 s1 s2 s3:
  (frameeq bound1 bound2 s1 s2) → (frameeq bound1 bound2 s2 s3) → (frameeq bound1 bound2 s1 s3).
Proof.
  unfold frameeq; intros; eapply eq_trans.
  eapply H; eauto.
  auto.
Qed.

Lemma frameeq_glue bound1 bound2 bound3 s1 s2:
  (frameeq bound1 bound2 s1 s2) → (frameeq (Zpos bound2) bound3 s1 s2) → (frameeq bound1 bound3 s1 s2).
Proof.
  unfold frameeq; intros H1 H2 x H3.
  case (Z_le_dec (Zpos bound2) (Zpos x)); intros.
  apply H2; omega.
  apply H1; omega.
Qed.

Lemma frameeq_teval (t: term): ∀ bound s s',
   tbounds bound t →
    frameeq 0 bound s s' →
      teval t s = teval t s'.
Proof.
  unfold frameeq; induction t; simpl; intuition.
  erewrite IHt1; eauto.
  erewrite IHt2; eauto.
  erewrite IHt; eauto.
Qed.

Hint Resolve frameeq_teval frameeq_Zle frameeq_trans frameeq_glue: echecker.

Lemma add_morphism bound1 bound2 x val1 val2 c1 c2:
  val1=val2 → frameeq bound1 bound2 c1 c2 → frameeq bound1 bound2 (add x val1 c1) (add x val2 c2).
Proof.
  unfold frameeq; intros H H0 x0 H1.
  unfold add. case (Positive_as_DT.eq_dec x x0); auto.
Qed.

Hint Resolve add_morphism: checker.

Lemma add_frameeq_out_1 bound1 bound2 s x y : Zpos x < bound1 → frameeq bound1 bound2 (add x y s) s.
Proof.
  unfold frameeq; intros H.
  intros; rewrite add_out; auto.
  omega.
Qed.

Lemma add_frameeq_out_2 bound1 bound2 s x y : Zpos bound2 ≤ Zpos x → frameeq bound1 bound2 (add x y s) s.
Proof.
  unfold frameeq; intros H.
  intros; rewrite add_out; auto.
  omega.
Qed.

Hint Resolve add_frameeq_out_1 add_frameeq_out_2: checker2.

Renaming of x1 by x2 in t
Fixpoint trename (t:term) (x1 x2: positive) : term
  := match t with
     | tvar x ⇒ if Positive_as_DT.eq_dec x1 (vid x) then tvar (mkvar (vtag x) x2) else t
     | tcte c ⇒ t
     | tbin op tl tr ⇒ tbin op (trename tl x1 x2) (trename tr x1 x2)
     | told t ⇒ trename t x1 x2
     | tapp f t ⇒ tapp f (trename t x1 x2)
     end.

Lemma Psucc_lift n: Zpos (n+1)=(Zpos n)+1.
Proof.
  auto.
Qed.
Hint Rewrite Psucc_lift: rchecker.

Lemma Zpos_Psucc_lt n: Zpos n < Zpos (n+1).
Proof.
  autorewrite with rchecker. omega.
Qed.
Hint Resolve Zpos_Psucc_lt: checker.
Hint Resolve Zlt_trans: echecker2.

Lemma Zpos_Psucc_le n: Zpos n ≤ Zpos (n+1).
Proof.
  autorewrite with rchecker. omega.
Qed.
Hint Resolve Zpos_Psucc_le: echecker.

Lemma tbounds_trename t: ∀ x1 x2, tbounds x2 t →
  tbounds (x2+1) (trename t x1 x2).
Proof.
  induction t; simpl; try (intuition; fail).
  unfold trename.
  case x; clear x; intros s x x1 x2; simpl.
  case (Positive_as_DT.eq_dec x1 x); simpl; eauto with checker echecker2.
Qed.
Hint Resolve tbounds_trename: checker.

Lemma trename_tbounds t: ∀ x1 x2 s dummy, tbounds x2 t →
  teval (trename t x1 x2) (add x2 (s x1) (add x1 dummy s)) = teval t s.
Proof.
  unfold teval; induction t; simpl; try (intuition; fail).
  unfold trename.
  case x; clear x; intros s x x1 x2; simpl.
  case (Positive_as_DT.eq_dec x1 x); simpl.
  intros; subst. auto with checker.
  intros; rewrite add_out; auto with checker.
  omega.
  simpl; intuition; rewrite IHt1; auto.
  rewrite IHt2; auto.
  intros; erewrite IHt; auto.
Qed.
Hint Rewrite trename_tbounds: rchecker.

Frame bound for conditions
Fixpoint cbounds (bound: positive) (c:cond): Prop :=
 match c with
 | basic b ⇒ True
 | atom oc tl tr ⇒ tbounds bound tl ∧ tbounds bound tr
 | bin og cl cr ⇒ cbounds bound cl ∧ cbounds bound cr
 | not c ⇒ cbounds bound c
 end.

Lemma cbounds_Zle c bound1:
   cbounds bound1 c → ∀ bound2:positive, (Zpos bound1) ≤ (Zpos bound2) → cbounds bound2 c.
Proof.
  induction c; simpl; intuition eauto with echecker.
Qed.

Hint Resolve cbounds_Zle: echecker.

Lemma frameeq_eval c: ∀ bound s s',
 frameeq 0 bound s s' →
   cbounds bound c →
     eval c s = eval c s'.
Proof.
  induction c; simpl; intuition.
  erewrite frameeq_teval; eauto.
  erewrite frameeq_teval with (s:=s); eauto.
  erewrite IHc1; eauto.
  erewrite IHc2; eauto.
  erewrite IHc; eauto.
Qed.

Lemma frameeq_eval_imp c bound s s':
   cbounds bound c →
     eval c s →
       frameeq 0 bound s s' →
         eval c s'.
Proof.
  intros; erewrite frameeq_eval in × |- ; eauto.
Qed.
Hint Resolve frameeq_eval_imp: echecker.

Lemma frameeq_eval_imp_s c bound s s':
   cbounds bound c →
     eval c s →
      frameeq 0 bound s' s →
         eval c s'.
Proof.
  intros; erewrite frameeq_eval; eauto.
Qed.
Hint Resolve frameeq_eval_imp_s: echecker.

Definition extend (c: cond) (bound1 bound2: positive) (s s': state): Prop :=
  ∃ sf, eval c sf ∧ (frameeq 0 bound1 sf s') ∧ (frameeq (Zpos bound1) bound2 sf s).

Fixpoint rename (c:cond) (x1 x2: positive) : cond
  := match c with
     | atom oc tl tr ⇒ atom oc (trename tl x1 x2) (trename tr x1 x2)
     | bin og cl cr ⇒ bin og (rename cl x1 x2) (rename cr x1 x2)
     | not c ⇒ not (rename c x1 x2)
     | _ ⇒ c
     end.

Lemma rename_cbounds c: ∀ x1 x2 s dummy, cbounds x2 c →
  eval (rename c x1 x2) (add x2 (s x1) (add x1 dummy s)) = eval c s.
Proof.
  induction c; simpl; intuition auto with checker.
  autorewrite with rchecker; auto.
  rewrite IHc1; auto.
  rewrite IHc2; auto.
  rewrite IHc; auto.
Qed.
Hint Rewrite rename_cbounds: rchecker.

Lemma cbounds_rename c: ∀ x1 x2, cbounds x2 c →
  cbounds (x2+1) (rename c x1 x2).
Proof.
  induction c; try (simpl; intuition; fail).
Qed.
Hint Resolve cbounds_rename: checker.

Computations on frame bounds
Lemma Zle_Pmax_l n1 n2: (Zpos n1) ≤ Zpos (Pmax n1 n2).
Proof.
  intros; rewrite Zpos_max.
  apply Zle_max_l.
Qed.

Lemma Zle_Pmax_r n1 n2: (Zpos n2) ≤ Zpos (Pmax n1 n2).
Proof.
  intros; rewrite Zpos_max.
  apply Zle_max_r.
Qed.

Hint Resolve Zle_Pmax_r Zle_Pmax_l: echecker.
Hint Resolve Zle_refl: checker.
Hint Resolve Zle_trans: echecker.
Hint Resolve Zlt_le_trans: echecker2.

Fixpoint tbound (t:term) (bound: positive): positive :=
 match t with
 | tvar x ⇒ Pmax bound ((vid x)+1)%positive
 | tcte c ⇒ bound
 | tbin op tl tr ⇒ tbound tl (tbound tr bound)
 | told t ⇒ tbound t bound
 | tapp f t ⇒ tbound t bound
 end.

Lemma tbound_monotonic t: ∀ bound, (Zpos bound) ≤ Zpos (tbound t bound).
Proof.
  induction t; simpl; intros; eauto with checker echecker.
Qed.

Hint Resolve tbound_monotonic: checker.

Lemma tbound_tbounds t: ∀ bound, (tbounds (tbound t bound) t).
Proof.
  induction t; simpl; intros; eauto with checker echecker echecker2.
Qed.

Hint Resolve tbound_tbounds: checker.

Fixpoint cbound (c:cond) (bound: positive): positive :=
 match c with
 | basic b ⇒ bound
 | atom oc tl tr ⇒ tbound tl (tbound tr bound)
 | bin og cl cr ⇒ cbound cl (cbound cr bound)
 | not c ⇒ cbound c bound
 end.

Lemma cbound_monotonic c: ∀ bound, (Zpos bound) ≤ Zpos (cbound c bound).
Proof.
  induction c; simpl; intros; eauto with checker echecker.
Qed.

Hint Resolve cbound_monotonic: checker.

Lemma cbound_cbounds c: ∀ bound, (cbounds (cbound c bound) c).
Proof.
  induction c; simpl; intuition eauto with checker echecker.
Qed.

Hint Resolve cbound_cbounds: checker.

Renaming using fresh variable

Record renaming := {
  rmap: PositiveMap.t var ;
  rbound: positive
}.

Definition rbounds bound (r: renaming) :=
 Zpos bound ≤ Zpos (rbound r) ∧
 ∀ x, try (PositiveMap.find x (rmap r)) (fun (x:var) ⇒ Zpos bound ≤ Zpos (vid x) < Zpos (rbound r)) True.

Lemma rbounds_rbound bound r : rbounds bound r → Zpos bound ≤ Zpos (rbound r).
Proof.
  unfold rbounds; intuition.
Qed.

Hint Resolve rbounds_rbound: checker.

Lemma rbounds_Zle bound1 bound2 r : rbounds bound2 r → Zpos bound1 ≤ Zpos bound2 → rbounds bound1 r.
Proof.
  unfold rbounds; intuition.
  eapply try_monotonic; eauto.
  simpl; intuition.
Qed.
Hint Resolve rbounds_Zle: echecker.

Definition rfind (x:var) (r: renaming) :=
 match PositiveMap.find (vid x) (rmap r) with
 | Some x ⇒ x
 | None ⇒ x
 end.

Lemma rbounds_rfind_up (x:var) r bound :
  rbounds bound r → Zpos (vid x) < Zpos (rbound r) → Zpos (vid (rfind x r)) < Zpos (rbound r).
Proof.
  unfold rbounds, rfind; intuition.
  generalize (H2 (vid x)).
  case (PositiveMap.find (vid x) (rmap r)); simpl; intuition.
Qed.

Lemma rbounds_rfind_down (x:var) r bound :
  rbounds bound r → Zpos (vid (rfind x r)) < Zpos bound → (rfind x r)=x.
Proof.
  unfold rbounds, rfind; intuition.
  generalize H0 (H2 (vid x)); clear H0 H2.
  case (PositiveMap.find (vid x) (rmap r)); simpl; intuition.
  assert (Zpos (vid x) ≠ Zpos (vid x)).
  omega.
  case H.
  auto.
Qed.

Lemma vid_rfind (x y: var) r: (vid x)=(vid y) → (vid (rfind x r))=(vid (rfind y r)).
Proof.
  unfold rfind. intros H. rewrite H.
  case (PositiveMap.find (vid y) (rmap r)); simpl; auto.
Qed.

Definition rlift (s:state) (r: renaming) : state :=
 fun x ⇒
 match PositiveMap.find x (rmap r) with
 | Some x ⇒ s (vid x)
 | None ⇒ s x
 end.

Lemma rlift_rfind x s r: rlift s r (vid x) = s (vid (rfind x r)).
Proof.
  unfold rlift, rfind. case (PositiveMap.find (vid x) (rmap r)); simpl; auto.
Qed.

Hint Rewrite rlift_rfind: rchecker.

Lemma rlift_frameeq bound s1 s2 r x :
  frameeq 0 bound (rlift s1 r) s2 → Zpos (vid x) < Zpos bound →
   s1 (vid (rfind x r)) = s2 (vid x).
Proof.
  unfold frameeq; intros H H1. rewrite <- H; intuition.
  autorewrite with rchecker.
  auto.
Qed.

Lemma rlift_add_out_2 bound x y s r: rbounds bound r →
  Zpos (rbound r) ≤ Zpos x → frameeq 0 (rbound r) (rlift (add x y s) r) (rlift s r).
Proof.
  unfold rbounds, rlift, frameeq. intuition.
  generalize (H2 x0).
  case (PositiveMap.find x0 (rmap r)); simpl; auto.
  intros; rewrite add_out; auto.
  omega.
  intros; rewrite add_out; auto.
  omega.
Qed.

Definition rempty (bound: positive): renaming :=
 {| rmap:=PositiveMap.empty _ ;
    rbound:=bound
   |}.

Lemma rempty_rbounds bound: rbounds bound (rempty bound).
Proof.
  unfold rbounds. simpl. intuition. rewrite PositiveMap.gempty; simpl; auto.
Qed.

Lemma rempty_rfind x bound : rfind x (rempty bound)=x.
Proof.
  unfold rempty, rfind; simpl.
  rewrite PositiveMap.gempty; simpl; auto.
Qed.

Hint Rewrite rempty_rfind: rchecker.

Lemma rempty_rlift s bound x: rlift s (rempty bound) x = s x.
Proof.
  unfold rempty, rlift; simpl. rewrite PositiveMap.gempty; simpl; auto.
Qed.

Hint Rewrite rempty_rlift: rchecker.

Definition fresh (x:var) (r: renaming): renaming :=
  let bound:=rbound r in
  {| rmap:= PositiveMap.add (vid x) (mkvar (vtag x) bound) (rmap r) ;
     rbound:= (bound+1)%positive
  |}.

Lemma fresh_rbounds bound x r: rbounds bound r → rbounds bound (fresh x r).
Proof.
  unfold rbounds, fresh; simpl; intuition.
  eauto with echecker.
  rewrite PositiveMapAdditionalFacts.gsspec.
  case (PositiveMap.E.eq_dec x0 (vid x)).
  intros; subst; simpl; intuition auto with checker.
  intros; eapply try_monotonic; eauto.
  simpl; intuition eauto with checker echecker2.
Qed.

Hint Resolve rbounds_rfind_up rbounds_rfind_down: echecker.
Hint Resolve rempty_rbounds fresh_rbounds: checker.

Lemma rfind_fresh_in x r: rfind x (fresh x r) = mkvar (vtag x) (rbound r).
Proof.
  unfold rfind, fresh; simpl.
  rewrite PositiveMap.add_1; auto.
  unfold PositiveMap.E.eq; auto.
Qed.

Hint Rewrite rfind_fresh_in: rchecker.

Lemma rfind_fresh r (x x':var): rfind x' (fresh x r) =
  if (PositiveMap.E.eq_dec (vid x') (vid x)) then mkvar (vtag x) (rbound r) else rfind x' r.
Proof.
 unfold rfind, fresh; simpl.
 rewrite PositiveMapAdditionalFacts.gsspec.
 case (PositiveMap.E.eq_dec (vid x') (vid x)); simpl; auto.
Qed.

Lemma rlift_fresh r (x1:var) s x2: rlift s (fresh x1 r) x2 = add (vid x1) (s (rbound r)) (rlift s r) x2.
Proof.
 unfold rlift, fresh; simpl.
 rewrite PositiveMapAdditionalFacts.gsspec.
 case (PositiveMap.E.eq_dec x2 (vid x1)); simpl.
 intros; subst; rewrite add_in; auto.
 intros; rewrite add_out2; auto.
Qed.

Lemma rlift_fresh_tech:
  ∀ bound r x dummy s, (rbounds bound r) →
   Zpos (vid x) < Zpos bound →
   frameeq 0 (rbound r)
    (rlift (add (rbound r) (s (vid (rfind x r))) (add (vid x) dummy s)) (fresh x r))
    (rlift s r).
Proof.
  unfold frameeq; intros.
  rewrite rlift_fresh.
  rewrite add_in.
  case (PositiveMap.E.eq_dec x0 (vid x)).
  intros; subst.
  rewrite add_in.
  autorewrite with rchecker; auto.
  intros; rewrite add_out2; auto.
  eapply eq_trans.
  eapply rlift_add_out_2; eauto with checker.
  unfold rlift, rbounds in × |- ×.
  intuition.
  generalize (H3 x0); clear H3.
  case (PositiveMap.find x0 (rmap r)); simpl.
  intros; rewrite add_out; auto.
  omega.
  intros; rewrite add_out2; auto.
Qed.


Fixpoint trsubst (t:term) r: term :=
  match t with
  | tvar x ⇒ tvar (rfind x r)
  | tcte c ⇒ t
  | tbin op tl tr ⇒ tbin op (trsubst tl r) (trsubst tr r)
  | told t ⇒ trsubst t r
  | tapp f t ⇒ tapp f (trsubst t r)
  end.

Lemma tbounds_trsubst t: ∀ bound r, rbounds bound r → tbounds (rbound r) t →
  tbounds (rbound r) (trsubst t r).
Proof.
  induction t; simpl; intuition eauto with echecker.
Qed.
Hint Resolve tbounds_trsubst: echecker.

Lemma trsubst_teval_rlift t: ∀ r s,
  teval (trsubst t r) s = teval t (rlift s r).
Proof.
  induction t; simpl; auto.
  intros; autorewrite with rchecker; auto.
  intros r s; rewrite IHt1. rewrite IHt2.
  auto.
  intros; rewrite IHt; auto.
Qed.
Hint Rewrite <- trsubst_teval_rlift: rchecker.

Lemma trsubst_rempty t: ∀ s bound,
  teval (trsubst t (rempty bound)) s = teval t s.
Proof.
  induction t; simpl; intuition.
  autorewrite with rchecker; auto.
  rewrite IHt1. rewrite IHt2; auto.
  rewrite IHt; auto.
Qed.
Hint Rewrite trsubst_rempty: rchecker.

Fixpoint rsubst (c:cond) r : cond
  := match c with
     | atom oc tl tr ⇒ atom oc (trsubst tl r) (trsubst tr r)
     | bin og cl cr ⇒ bin og (rsubst cl r) (rsubst cr r)
     | not c ⇒ not (rsubst c r)
     | _ ⇒ c
     end.

Lemma cbounds_rsubst c: ∀ bound r, rbounds bound r → cbounds (rbound r) c →
  cbounds (rbound r) (rsubst c r).
Proof.
  induction c; simpl; intuition; eauto with echecker.
Qed.
Hint Resolve cbounds_rsubst: echecker.

Lemma rsubst_rempty c: ∀ s bound,
  eval (rsubst c (rempty bound)) s = eval c s.
Proof.
  induction c; simpl; intuition.
  autorewrite with rchecker; auto.
  rewrite IHc1. rewrite IHc2; auto.
  rewrite IHc. auto.
Qed.
Hint Rewrite rsubst_rempty: rchecker.

Lemma rsubst_eval_rlift c: ∀ r s,
  eval (rsubst c r) s = eval c (rlift s r).
Proof.
  induction c; simpl; intuition.
  autorewrite with rchecker; auto.
  rewrite IHc1; rewrite IHc2; auto.
  erewrite IHc; auto.
Qed.
Hint Rewrite <- rsubst_eval_rlift: rchecker.

Lemma rsubst_fresh_cbounds c: ∀ bound r (x:var) dummy s, (rbounds bound r) → cbounds (rbound r) c →
  Zpos (vid x) < Zpos bound →
  eval (rsubst c (fresh x r)) (add (rbound r) (s (vid (rfind x r))) (add (vid x) dummy s)) = eval (rsubst c r) s.
Proof.
  intros. rewrite rsubst_eval_rlift. rewrite rsubst_eval_rlift.
  eapply frameeq_eval; eauto.
  eapply rlift_fresh_tech; eauto.
Qed.

Handling of "old"

Lemma frameeq_oteval (t: term): ∀ bound old new old' new',
   tbounds bound t →
   tbounds bound t →
    frameeq 0 bound old old' →
     frameeq 0 bound new new' →
      oteval t old new = oteval t old' new'.
Proof.
  unfold frameeq; induction t; simpl; intuition.
  erewrite IHt1; eauto.
  erewrite IHt2; eauto.
  eauto with echecker.
  erewrite IHt; eauto.
Qed.

Lemma frameeq_oeval c: ∀ bound old new old' new',
    frameeq 0 bound old old' →
     frameeq 0 bound new new' →
      cbounds bound c →
      cbounds bound c →
       oeval c old new = oeval c old' new'.
Proof.
  induction c; simpl; intuition.
  erewrite frameeq_oteval; eauto.
  erewrite frameeq_oteval with (new:=new); eauto.
  erewrite IHc1; eauto.
  erewrite IHc2; eauto.
  erewrite IHc; eauto.
Qed.

Fixpoint otrsubst (t:term) r: term :=
  match t with
  | tbin op tl tr ⇒ tbin op (otrsubst tl r) (otrsubst tr r)
  | told t ⇒ trsubst t r
  | tapp f t ⇒ tapp f (otrsubst t r)
  | _ ⇒ t
  end.

Lemma tbounds_otrsubst t: ∀ bound r, rbounds bound r → tbounds (rbound r) t →
  tbounds (rbound r) (otrsubst t r).
Proof.
  induction t; simpl; intuition eauto with echecker.
Qed.
Hint Resolve tbounds_otrsubst: echecker.

Lemma otrsubst_rempty t: ∀ s bound,
  teval (otrsubst t (rempty bound)) s = teval t s.
Proof.
  induction t; simpl; intuition.
  rewrite IHt1. rewrite IHt2; auto.
  autorewrite with rchecker; auto.
  rewrite IHt; auto.
Qed.
Hint Rewrite otrsubst_rempty: rchecker.

Lemma otrsubst_eval_rlift t: ∀ r s,
  teval (otrsubst t r) s = oteval t (rlift s r) s.
Proof.
  induction t; simpl; intuition.
  rewrite IHt1; rewrite IHt2; auto.
  autorewrite with rchecker; auto.
  rewrite IHt; auto.
Qed.
Hint Rewrite <- otrsubst_eval_rlift: rchecker.

Fixpoint orsubst (c:cond) r : cond
  := match c with
     | atom oc tl tr ⇒ atom oc (otrsubst tl r) (otrsubst tr r)
     | bin og cl cr ⇒ bin og (orsubst cl r) (orsubst cr r)
     | not c ⇒ not (orsubst c r)
     | _ ⇒ c
     end.

Lemma cbounds_orsubst c: ∀ bound r, rbounds bound r → cbounds (rbound r) c →
  cbounds (rbound r) (orsubst c r).
Proof.
  induction c; simpl; intuition; eauto with echecker.
Qed.
Hint Resolve cbounds_orsubst: echecker.

Lemma orsubst_rempty c: ∀ s bound,
  eval (orsubst c (rempty bound)) s = eval c s.
Proof.
  induction c; simpl; intuition.
  autorewrite with rchecker; auto.
  rewrite IHc1. rewrite IHc2; auto.
  rewrite IHc; auto.
Qed.
Hint Rewrite orsubst_rempty: rchecker.

Lemma orsubst_eval_rlift c: ∀ r s,
  eval (orsubst c r) s = oeval c (rlift s r) s.
Proof.
  induction c; simpl; intuition.
  rewrite otrsubst_eval_rlift; rewrite otrsubst_eval_rlift; auto.
  rewrite IHc1; rewrite IHc2; eauto.
  rewrite IHc; auto.
Qed.

Swap of two variables
Definition swap (x y: var) bound :renaming :=
  {| rmap:= PositiveMap.add (vid x) y (PositiveMap.add (vid y) x (PositiveMap.empty _));
     rbound:= bound
  |}.

Lemma swap_rbounds bound1 bound2 (x y: var): Zpos bound1 ≤ Zpos (vid x) < Zpos bound2 → Zpos bound1 ≤ Zpos (vid y) < Zpos bound2 → rbounds bound1 (swap x y bound2).
Proof.
  unfold rbounds, swap; simpl; intuition.
  rewrite PositiveMapAdditionalFacts.gsspec.
  case (PositiveMap.E.eq_dec x0 (vid x)); simpl; auto.
  intros; rewrite PositiveMapAdditionalFacts.gsspec.
  case (PositiveMap.E.eq_dec x0 (vid y)); simpl; auto.
  intros; rewrite PositiveMap.gempty; simpl; auto.
Qed.

Lemma swap_rfind x y z bound:
  rfind z (swap x y bound) =
   if PositiveMap.E.eq_dec (vid z) (vid x)
   then y
   else if PositiveMap.E.eq_dec (vid z) (vid y)
   then x
   else z.
Proof.
  unfold swap, rfind; simpl.
  rewrite PositiveMapAdditionalFacts.gsspec.
  case (PositiveMap.E.eq_dec (vid z) (vid x)); auto.
  rewrite PositiveMapAdditionalFacts.gsspec.
  case (PositiveMap.E.eq_dec (vid z) (vid y)); auto.
  intros; rewrite PositiveMap.gempty; intuition.
Qed.

Lemma swap_rfind_1 x y bound: rfind x (swap x y bound)=y.
Proof.
  unfold swap, rfind; simpl.
  rewrite PositiveMap.add_1; intuition.
Qed.

Lemma swap_rfind_2 x y bound: (vid y)<>(vid x) → rfind y (swap x y bound)=x.
Proof.
  intros H; rewrite swap_rfind.
  case (PositiveMap.E.eq_dec (vid y) (vid x)).
  intros; case H; auto.
  case (PositiveMap.E.eq_dec (vid y) (vid y)); auto.
  intros H0; case H0; auto.
Qed.

Hint Rewrite swap_rfind_1 swap_rfind_2: rchecker.

Lemma swap_rfind_3 x y bound z: (vid z)<>(vid x) → (vid z)<>(vid y) → rfind z (swap x y bound)=z.
Proof.
  intros H H0; rewrite swap_rfind.
  case (PositiveMap.E.eq_dec (vid z) (vid x)).
  intros; case H; auto.
  case (PositiveMap.E.eq_dec (vid z) (vid y)).
  intros; case H0; auto.
  auto.
Qed.

Lemma swap_rlift s x y z bound: rlift s (swap x y bound) z = add (vid x) (s (vid y)) (add (vid y) (s (vid x)) s) z.
Proof.
  unfold rlift, swap; simpl.
 rewrite PositiveMapAdditionalFacts.gsspec.
 case (PositiveMap.E.eq_dec z (vid x)).
 intros; subst; rewrite add_in; auto.
 intros; rewrite add_out2; auto.
 rewrite PositiveMapAdditionalFacts.gsspec.
 case (PositiveMap.E.eq_dec z (vid y)).
 intros; subst; rewrite add_in; auto.
 intros; rewrite add_out2; auto.
 rewrite PositiveMap.gempty; simpl; auto.
Qed.