ITree.Extra.Secure.SecureEqWcompat

From Coq Require Import Morphisms.

From ITree Require Import
     Axioms
     ITree
     ITreeFacts.

From ITree.Extra Require Import
     Secure.SecureEqHalt
.

From Paco Require Import paco.

Import Monads.
Import MonadNotation.
Local Open Scope monad_scope.

Lemma eqit_secureC_wcompat_id : b1 b2 E R1 R2 (RR : Prop )
      Label priv l
, wcompatible2 (@secure_eqit_ E Label priv RR l id)
                                         (eqitC RR ) .
Proof.
  econstructor. pmonauto_itree.
  intros. destruct PR.
  punfold EQVl. punfold EQVr. unfold_eqit. red in REL. red.
  hinduction REL before r; intros; clear ; try inv CHECK.
  - genobs_clear . genobs_clear .
    remember (RetF ) as x.
    hinduction EQVl before r; intros; inv Heqx; eauto with itree.
    remember (RetF ) as y.
    hinduction EQVr before r; intros; inv Heqy; eauto with itree.
  - remember (TauF ) as y.
    hinduction EQVl before r; intros; inv Heqy; try inv CHECK; subst; eauto with itree.
    remember (TauF ) as x.
    hinduction EQVr before r; intros; inv Heqx; try inv CHECK; subst; eauto with itree.
    pclearbot. constructor. gclo. econstructor; eauto with paco.
  - eapply IHREL; eauto.
    remember (TauF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    constructor; auto. pclearbot. pstep_reverse.
  - eapply IHREL; eauto.
    remember (TauF ) as x.
    hinduction EQVr before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    constructor; auto. pclearbot. pstep_reverse.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    ddestruction. subst. remember (VisF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; eauto with itree.
    ddestruction. subst. constructor; auto.
    intros. apply gpaco2_clo. pclearbot. econstructor; eauto with itree. apply H.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto with itree.
    ddestruction. subst. pclearbot. remember (TauF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; eauto with itree.
    pclearbot.
    unpriv_co. gclo. econstructor; eauto with paco itree. gfinal.
    left. apply H.
  - remember (TauF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto with itree.
    remember (VisF e ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; eauto with itree.
    ddestruction. subst.
    pclearbot. unpriv_co. gclo. econstructor; eauto with paco itree.
    gfinal. left. apply H.
  - remember (VisF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto with itree.
    ddestruction. subst. remember (VisF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; eauto with itree.
    ddestruction. subst. unpriv_co. gclo. pclearbot.
    econstructor; eauto with itree paco. gfinal. left. apply H.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    ddestruction. subst. pclearbot. unpriv_ind.
    eapply ; eauto. pstep_reverse.
  - remember (VisF e ) as x.
    hinduction EQVr before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    ddestruction. subst. pclearbot. unpriv_ind.
    eapply ; eauto. pstep_reverse.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    ddestruction. subst. remember (TauF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; eauto with itree.
    pclearbot. unpriv_halt. gclo. econstructor; eauto with paco.
    pfold. constructor. red; auto.
  - remember (VisF e ) as x.
    hinduction EQVr before r; intros; inv Heqx; try inv CHECK; eauto with itree.
    ddestruction. subst. remember (TauF ) as y.
    hinduction EQVl before r; intros; inv Heqy; try inv CHECK; eauto with itree.
    pclearbot. unpriv_halt. gclo. econstructor; eauto with paco.
    pfold. constructor. red; auto.
  - remember (VisF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; try contra_size; eauto with itree.
    ddestruction. subst. remember (VisF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; eauto with itree.
    ddestruction. subst. unpriv_halt. pclearbot.
    gclo. econstructor 1 with ( := Vis ); eauto with paco itree.
    + pfold. constructor; left; auto.
    + gfinal. left. apply H.
  - remember (VisF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; try contra_size; eauto with itree.
    ddestruction. subst. remember (VisF ) as y.
    hinduction EQVr before r; intros; inv Heqy; try inv CHECK; eauto with itree.
    ddestruction. subst. unpriv_halt. pclearbot.
    gclo. econstructor 1 with ( := Vis ); eauto with paco itree.
    + pfold. constructor. left. auto.
    + gfinal. left. apply H.
Qed.


#[export] Hint Resolve eqit_secureC_mon : paco.

Lemma eqit_secure_shalt_refl : E R1 R2 b1 b2 (RR : Prop) Label priv l A (e : E A) k1 k2,
    (¬ leq (priv _ e) l) empty A
    eqit_secure Label priv RR l (Vis e ) (Vis e ).
Proof.
  intros. pfold. red. cbn. unpriv_halt. contra_size.
Qed.


Ltac inv_vis_secure := ddestruction; subst;
   try contradiction; try contra_size.
Ltac clear_trivial :=
  repeat match goal with
  | H : empty ?A, H' : a : ?A, ?P |- _clear H' end.
Ltac eqit_secureC_halt_cases E := repeat (pclearbot; clear_trivial; match goal with
     | |- _ (TauF _ ) (TauF _) ⇒ constructor; gclo; pclearbot
     | |- eqit_secureC ?RR ?Label ?priv ?l ? ? _ ? ?econstructor; clear_trivial; eauto with paco
     | H : secure_eqitF ?Label ?priv ?RR ? ? ?l _ _ (observe ?) _ |- eqit_secure ?Label ?priv ?RR ? ? ?l ? ?pfold; eauto with itree
     | H : nonempty ?A |- _ _ (@VisF _ _ _ ?A ?e _ ) ⇒ unpriv_co; gclo ; pclearbot
     | H : nonempty ?A |- _ (@VisF _ _ _ ?A ?e _ ) _unpriv_co; gclo ; pclearbot
     | H : empty ?A |- _ _ (@VisF _ _ _ ?A ?e _ ) ⇒ unpriv_halt; gclo ; pclearbot
     | H : empty ?A |- _ (@VisF _ _ _ ?A ?e _ ) _unpriv_halt; gclo ; pclearbot
     | |- eqit_secureC ?RR ?Label ?priv ?l ? ? _ ? ?econstructor; eauto with paco

     | H : a, secure_eqitF ?Label ?priv ?RR ? ? ?l _ _ _ (observe ?),
        : observe ? = VisF ?e ?k |- eqit_secure _ _ _ _ _ _ _ (Vis ?e ?k) ⇒
       rewrite in H; pfold; apply H
     | HA : empty ?A, HB : empty ?B, : E ?A |-
                       eqit_secure _ _ _ _ _ _ (go (@VisF _ _ _ ?A _ _ )) (go (@VisF _ _ _ ?B _ _ ))
                       ⇒ pfold; red; cbn; unpriv_halt; try contra_size
     | H : a : ?A, _ (?k a) ?t |- eqit_secure _ _ _ _ _ _ (?k ?a) (?t) ⇒ red; eauto with itree
     | H : a : ?A, _ ?t (?k a) |- eqit_secure _ _ _ _ _ _ ?t (?k ?a) ⇒ red; eauto with itree
     | H : (a : ?A) (b : ?B), _ (? a) (? b) |-
                                                                        eqit_secure _ _ _ _ _ _ (? ?a) (? ?b) ⇒ red; eauto with itree
     | H : _ (observe ?t) (VisF ? ?) |- _ ?t ?rewrite itree_eta' in H; apply H
     | a : ?A, H : empty ?A |- _contra_size
     | a : ?A |- nonempty ?Aconstructor; auto
     | HA : empty ?A, HB : empty ?B, Heq : observe ?t = (@VisF _ _ _ ?A _ _) |-
          _ _ _ _ (?t ) (go (@VisF _ _ _ ?B _ _)) ⇒ gfinal; right; pstep; red; cbn; rewrite Heq; unpriv_halt
     | HA : empty ?A, HB : empty ?B |-
          _ _ _ _ (go (@VisF _ _ _ ?A _ _) ) (go (@VisF _ _ _ ?B _ _)) ⇒ gfinal; right; pstep; red; cbn; unpriv_halt
     | H : (a : ?A), _ (observe (?k a) ) observe (?t), Heq : observe ?t = VisF ?e ? |-
        eqit_secure _ _ _ _ _ _ (?k ?a) _rewrite itree_eta' in Heq; rewrite Heq in H; pfold; apply H
     | H : a : ?A, ?P (observe (?k a) ) (observe ?t), Heq : observe ?t = VisF ?e ? |-
                                                        eqit_secure _ _ _ _ _ _ (?k ?a) _
                                          rewrite itree_eta' in Heq; rewrite Heq in H; pfold; apply H
  end;
  clear_trivial)
.

Ltac find_size A :=
  match goal with
  | H : nonempty A |- _idtac
  | H : empty A |- _idtac
  | |- _destruct (classic_empty A); try contra_size end.

Ltac produce_elem H A := inv H; assert (nonempty A); try (constructor; auto with itree; fail).

Ltac fold_secure :=
  change ( (_ ?LB ?priv ?RR ?b ?fls ?l _) ?a) with (eqit_secure LB priv RR b fls l) in ×.

(* Specialize some hypothesis with the assumption x *)
Ltac spew x :=
  let T := type of x in
  repeat lazymatch goal with
  | [ : (_ : T), _ |- _ ] ⇒ specialize ( x)
  end.

Lemma eqit_secureC_wcompat_id' : b1 b2 E R1 R2 (RR : Prop )
      Label priv l,
    wcompatible2 (@secure_eqit_ E Label priv RR l id)
                                         (eqit_secureC RR Label priv l ) .
Proof.
  econstructor.
  { red. intros. eauto with paco. }
  intros. dependent destruction PR.
  punfold EQVl. punfold EQVr. red in EQVl. red in EQVr. red in REL. red.
  hinduction REL before r; intros; clear ; try inv CHECK.
  - remember (RetF ) as x. hinduction EQVl before r; intros; subst; try inv Heqx; eauto with itree.
    remember (RetF ) as y. hinduction EQVr before r; intros; subst; try inv Heqy; eauto with itree.
    rewrite itree_eta' at 1. unpriv_ind. eapply ; eauto.
  - remember (TauF ) as x. hinduction EQVl before r; intros; subst; try inv Heqx;
    try inv CHECK; eauto with itree.
    + remember (TauF ) as y. pclearbot.
      (* think I might have a lead on the problem, should H0 have vclo not id here?*)
      hinduction EQVr before r; intros; subst; try inv Heqy;
      try inv CHECK; pclearbot; try fold_secure; eauto with itree.
      × constructor. gclo. econstructor; eauto. gfinal; eauto.
      × unpriv_co. gclo. econstructor; eauto. gfinal; eauto.
      × rewrite itree_eta' at 1. unpriv_ind. eauto.
      × unpriv_halt. gclo. econstructor; eauto. gfinal; eauto.
    + remember (TauF ) as y. pclearbot.
      hinduction EQVr before r; intros; subst; try inv Heqy;
      try inv CHECK; pclearbot; repeat fold_secure; eauto with itree.
      × unpriv_co. gclo. econstructor; eauto. gfinal; eauto.
      × unpriv_co. gclo. econstructor; eauto. gfinal; eauto.
      × rewrite itree_eta' at 1. unpriv_ind. eauto.
      × unpriv_halt. gclo. econstructor; eauto. gfinal; eauto.
   + remember (TauF ) as y. pclearbot.
      hinduction EQVr before r; intros; subst; try inv Heqy;
      try inv CHECK; pclearbot; repeat fold_secure; eauto with itree.
      × unpriv_halt. gclo. econstructor; eauto. gfinal; eauto.
      × unpriv_halt. gclo. econstructor; eauto. gfinal; eauto.
      × rewrite itree_eta' at 1. unpriv_ind. eauto.
      × unpriv_halt. contra_size.
 - eapply IHREL; eauto.
   remember (TauF ) as y. hinduction EQVl before r; intros; inv Heqy; try inv CHECK; eauto with itree.
   + constructor; auto. pclearbot. pstep_reverse.
   + unpriv_ind. pclearbot. pstep_reverse.
   + pclearbot. punfold H.
 - eapply IHREL; eauto.
   remember (TauF ) as y. hinduction EQVr before r; intros; inv Heqy; try inv CHECL; eauto with itree.
   + constructor; auto. pclearbot. pstep_reverse.
   + unpriv_ind. pclearbot. pstep_reverse.
   + pclearbot. punfold H.
 - remember (VisF e ) as x.
   hinduction EQVl before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; eauto with itree.
   remember (VisF ) as y.
   hinduction EQVr before r; intros; inv Heqy; try inv CHECK; inv_vis_secure; eauto with itree.
   + pclearbot. constructor; auto. intros. gclo. econstructor; eauto.
     apply . apply H. gfinal; left; apply .
   + rewrite itree_eta' at 1. unpriv_ind. eapply ; eauto.
 - unfold id in H. remember (VisF e ) as x.
   hinduction EQVl before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; eauto with itree.
   + pclearbot. remember (TauF ) as y.
     hinduction EQVr before r; intros; inv Heqy; try inv CHECK; repeat fold_secure; eauto with itree.
     × constructor. gclo. pclearbot. inv SIZECHECK. spew a. econstructor; eauto. gfinal; eauto.
     × unpriv_co. gclo. pclearbot. inv . spew ; spew a. econstructor; eauto.
       gfinal; eauto.
     × rewrite itree_eta' at 1. unpriv_ind. eauto.
     × unpriv_halt. pclearbot. inv .
       gclo. spew a. econstructor; eauto. gfinal; eauto.
   + pclearbot. pclearbot. inv SIZECHECK. remember (TauF ) as y.
     hinduction EQVr before r; intros; inv Heqy; try inv CHECK; repeat fold_secure; eauto with itree.
     × unpriv_co. gclo. pclearbot. spew . spew a. econstructor; eauto. gfinal; eauto.
     × unpriv_co. gclo. pclearbot. fold_secure. spew ; spew a. econstructor; eauto. gfinal; eauto.
     × rewrite itree_eta' at 1. unpriv_ind. eauto.
     × pclearbot. unpriv_halt. gclo. spew . spew a. econstructor; eauto. gfinal; eauto.
  + pclearbot. inv . remember (TauF ) as y.
     hinduction EQVr before r; intros; inv Heqy; try inv CHECK; repeat fold_secure; eauto with itree.
     × unpriv_halt. gclo. pclearbot. spew a; econstructor; eauto.
       gfinal; eauto.
     × unpriv_halt. gclo. pclearbot. fold_secure. spew a. econstructor; eauto. gfinal; eauto.
     × rewrite itree_eta' at 1. unpriv_ind. eauto.
     × pclearbot. unpriv_halt. contra_size.
 - unfold id in H. remember (VisF e ) as x.
   hinduction EQVr before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; eauto with itree.
   + pclearbot. remember (TauF ) as y.
     hinduction EQVl before r; intros; inv Heqy; try inv CHECK; eauto with itree; repeat fold_secure.
     × constructor. gclo. pclearbot. fold_secure. inv SIZECHECK.
       spew a; econstructor; eauto. gfinal; eauto.
     × unpriv_co. gclo. pclearbot. fold_secure. inv . spew a; spew . econstructor; eauto.
       gfinal; eauto.
     × rewrite itree_eta'. unpriv_ind. eauto.
     × unpriv_halt. pclearbot. inv .
       gclo. spew a; econstructor; eauto. gfinal; eauto.
   + pclearbot. pclearbot. inv SIZECHECK. remember (TauF ) as y.
     hinduction EQVl before r; intros; inv Heqy; try inv CHECK; repeat fold_secure; eauto with itree.
     × unpriv_co. gclo. pclearbot. spew ; spew a. econstructor; eauto. gfinal; eauto.
     × unpriv_co. gclo. pclearbot. spew b; spew a; spew ; econstructor; eauto.
       gfinal; eauto.
     × rewrite itree_eta'. unpriv_ind. eauto.
     × pclearbot. unpriv_halt. gclo. spew a. econstructor; eauto. gfinal; eauto.
  + pclearbot. inv . remember (TauF ) as y.
     hinduction EQVl before r; intros; inv Heqy; try inv CHECK; eauto with itree.
     × unpriv_halt. gclo. pclearbot. fold_secure. spew a. econstructor; eauto.
       gfinal; eauto.
     × unpriv_halt. gclo. pclearbot. fold_secure. spew a. econstructor; eauto.
       gfinal; eauto.
     × rewrite itree_eta'. unpriv_ind. eauto.
     × pclearbot. unpriv_halt. contra_size.
 - unfold id in H. remember (VisF ) as x.
   hinduction EQVr before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; eauto with itree; pclearbot; fold_secure.
   1: inv ; inv ; remember (VisF ) as y.
   2: inv ; inv ; remember (VisF ) as y.
   3: inv ; inv ; remember (VisF ) as y.
   all: spew a; spew .
   all: hinduction EQVl before r; intros; inv Heqy; try inv CHECK; inv_vis_secure; subst;
     eauto with itree; try (eqit_secureC_halt_cases E; fail).
   all: rewrite itree_eta'; unpriv_ind; auto with itree; eauto.
 - inv SIZECHECK. eapply ; eauto. Unshelve. all : auto.
   remember (VisF e ) as x. clear .
   hinduction EQVl before r; intros; inv Heqx; inv_vis_secure; try inv CHECK; pclearbot; eauto with itree.
   + constructor; auto. pstep_reverse.
   + unpriv_ind. pstep_reverse.
   + rewrite itree_eta' at 1 . pstep_reverse.
 - inv SIZECHECK. eapply ( a); eauto.
   remember (VisF e ) as x. clear .
   hinduction EQVr before r; intros; inv Heqx; inv_vis_secure; try inv CHECK; pclearbot; eauto with itree.
   + constructor; auto. pstep_reverse.
   + unpriv_ind. pstep_reverse.
   + rewrite itree_eta' at 1 . pstep_reverse.
 - remember (TauF ) as x.
   hinduction EQVr before r; intros; inv Heqx; try inv CHECK; pclearbot; eauto with itree;
   inv EQVl; inv_vis_secure; eqit_secureC_halt_cases E.
   + pclearbot. find_size ; eqit_secureC_halt_cases E.
   + pclearbot. find_size ; eqit_secureC_halt_cases E.
 - remember (TauF ) as x.
   hinduction EQVl before r; intros; inv Heqx; try inv CHECK; pclearbot; eauto with itree;
   inv EQVr; inv_vis_secure;
   eqit_secureC_halt_cases E.
   + find_size ; eqit_secureC_halt_cases E.
   + find_size ; eqit_secureC_halt_cases E.
 - unfold id in H. remember (VisF ) as x.
   hinduction EQVr before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; pclearbot; eauto with itree;
   inv EQVl; inv_vis_secure;
   (* maybe I should just write a new one *)
   do 2 (
   repeat match goal with | H : nonempty ?A |- _inv H end;
   match goal with
   | : E ?A, : E ?B, : E ?C, : E ?D |- _
     find_size A ; find_size B; find_size C ; find_size D ; try contra_size
   | : E ?A, : E ?B, : E ?C |- _
     find_size A ; find_size B; find_size C ; try contra_size
   | : E ?A, : E ?B |- _
      find_size A ; find_size B; try contra_size
   | : E ?A |- _
     find_size A ; try contra_size
   end);
   eqit_secureC_halt_cases E; try (eapply eqit_secure_shalt_refl; eauto); eqit_secureC_halt_cases E;
   try apply ; try apply H; eqit_secureC_halt_cases E.
   Unshelve. all : auto.
 - unfold id in H. remember (VisF ) as x.
   hinduction EQVl before r; intros; inv Heqx; try inv CHECK; inv_vis_secure; pclearbot; eauto with itree;
     inv EQVr; inv_vis_secure;
       do 2 (
            repeat match goal with | H : nonempty ?A |- _inv H end;
            match goal with
            | : E ?A, : E ?B, : E ?C, : E ?D |- _
              find_size A ; find_size B; find_size C ; find_size D ; try contra_size
            | : E ?A, : E ?B, : E ?C |- _
              find_size A ; find_size B; find_size C ; try contra_size
            | : E ?A, : E ?B |- _
              find_size A ; find_size B; try contra_size
            | : E ?A |- _
              find_size A ; try contra_size
            end);
       eqit_secureC_halt_cases E; try (eapply eqit_secure_shalt_refl; eauto); eqit_secureC_halt_cases E;
   try apply ; try apply H; eqit_secureC_halt_cases E.
   Unshelve. all: auto.
Qed.


#[export] Hint Resolve eqit_secureC_wcompat_id : paco.

#[global] Instance geuttgen_cong_secure_eqit {E} {Label priv l} {R1 R2 : Type} {RR1 : Prop}
    {RR2 : Prop} {RS : Prop} (b1 b2 : bool) {r rg} :
    ( (x x' : ) (y : ), ( x x' : Prop) (RS x' y : Prop) RS x y)
    ( (x : ) (y y' : ), ( y y' : Prop) RS x y' RS x y)
    Proper (@eq_itree E eq_itree flip impl)
           ( (secure_eqit_ Label priv RS l id) (eqitC RS ) r rg ).
Proof.
  repeat intro. gclo. econstructor; eauto.
  - eapply eqit_mon, ; eauto; discriminate.
  - eapply eqit_mon, ; eauto; discriminate.
Qed.


#[global] Instance geuttgen_cong_secure_eqit' {E} {Label priv l} {R1 R2 : Type} {RR1 : Prop}
    {RR2 : Prop} {RS : Prop} (b1 b2 : bool) {r rg} :
    ( (x x' : ) (y : ), ( x x' : Prop) (RS x' y : Prop) RS x y)
    ( (x : ) (y y' : ), ( y y' : Prop) RS x y' RS x y)
    Proper (@eqit_secure E Label priv false false l
             eqit_secure Label priv false false l flip impl)
           ( (secure_eqit_ Label priv RS l id) (eqit_secureC RS Label priv l ) r rg ).
Proof.
  repeat intro. gclo. econstructor; eauto.
  - eapply secure_eqit_mon, ; eauto. intros; discriminate.
  - eapply secure_eqit_mon, ; eauto. intros; discriminate.
Qed.


#[global] Instance geutt_cong_euttge:
   {E : Type Type} Label priv l b1 b2 {R1 R2 : Type} {RR1 : Prop}
    {RR2 : Prop} {RS : Prop}
    (r rg : x : itree E , (fun _ : itree E itree E ) x Prop),
  ( (x x' : ) (y : ), ( x x' : Prop) (RS x' y : Prop) RS x y)
  ( (x : ) (y y' : ), ( y y' : Prop) RS x y' RS x y)
  Proper (euttge euttge flip impl)
    ( (secure_eqit_ Label priv RS l id) (eqitC RS true true) r rg).
Proof.
  repeat intro. gclo. econstructor; eauto.
Qed.


#[global] Instance geutt_eq_cong_euttge:
   {E : Type Type} Label priv l b1 b2 {R1 R2 : Type} r rg RS ,
    Proper ( @euttge E eq @euttge E eq flip impl)
           ( (secure_eqit_ Label priv RS l id) (eqitC RS true true) r rg ).
Proof.
  repeat intro. eapply geutt_cong_euttge; eauto; intros; subst; auto.
Qed.