From Undecidability Require Import TMTac TM.Util.Prelim.
From Undecidability.TM Require Export Compound.Multi Combinators.Combinators.
From Undecidability.TM.Hoare Require Import HoareLogic HoareRegister.



Lemma Nop_Spec (sig : finType) (n : ) (P : Assert sig n) :
  Triple P Nop ( _ P).
Proof.
  eapply TripleI,Realise_monotone.
  { TM_Correct. }
  { intros tin ([], tout) . hnf. auto. }
Qed.


Lemma Nop_SpecT (sig : finType) (n : ) (P : Assert sig n) :
  TripleT P 0 Nop ( _ P).
Proof.
  split.
  - eapply Consequence_pre. apply Nop_Spec. firstorder.
  - eapply TerminatesIn_monotone.
    + TM_Correct.
    + firstorder.
Qed.


Lemma Nop_SpecT_con (sig : finType) (n : ) (P : Assert sig n) k :
  TripleT P k Nop ( _ P).
Proof.
  eapply ConsequenceT_pre.
  - apply Nop_SpecT.
  - auto.
  - .
Qed.



Lemma Relabel_Spec (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (Q : Assert sig n) (pM : pTM sig n) (f : ) :
  Triple P pM Q
  Triple P (Relabel pM f) ( y' t y'', y' = f y'' Q y'' t).
Proof.
  intros HT. eapply TripleI, Realise_monotone.
  { TM_Correct. apply HT. }
  { intros tin (yout, tout) H. TMSimp. intros. eauto. }
Qed.


Lemma Relabel_Spec_con (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (Q : Assert sig n) (Q' : Assert sig n) (pM : pTM sig n) (f : ) :
  Triple P pM Q
  ( yout, Entails (Q yout) (Q' (f yout)))
  Triple P (Relabel pM f) Q'.
Proof.
  intros.
  eapply Consequence_post.
  - apply Relabel_Spec; eauto.
  - setoid_rewrite Entails_iff in . setoid_rewrite Entails_iff. intros. TMSimp. eauto.
Qed.


Lemma Relabel_SpecT (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (k : ) (Q : Assert sig n) (pM : pTM sig n) (f : ) :
  TripleT P k pM Q
  TripleT P k (Relabel pM f) ( y' t y'', y' = f y'' Q y'' t).
Proof.
  split.
  - apply Relabel_Spec; eauto.
  - eapply TerminatesIn_monotone.
    + TM_Correct. apply H.
    + firstorder.
Qed.


Lemma Relabel_SpecT_con (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (k : ) (Q : Assert sig n) (Q' : Assert sig n) (pM : pTM sig n)
      (f : ) :
  TripleT P k pM Q
  ( yout, Entails (Q yout) (Q' (f yout)))
  TripleT P k (Relabel pM f) Q'.
Proof.
  intros.
  eapply ConsequenceT_post.
  - apply Relabel_SpecT; eauto.
  - setoid_rewrite Entails_iff in . setoid_rewrite Entails_iff. intros. TMSimp. firstorder.
Qed.



Lemma Return_Spec (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (Q : Assert sig n) (pM : pTM sig n) (y : ) :
  Triple P pM Q
  Triple P (Return pM y) ( y' t y' = y y'', Q y'' t).
Proof.
  intros HT. eapply TripleI, Realise_monotone.
  { TM_Correct. apply HT. }
  { intros tin (yout, tout) H. TMSimp. intros. eauto. }
Qed.


Lemma Return_Spec_con (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (Q : Assert sig n) (Q' : Assert sig n) (pM : pTM sig n) (y : ) :
  Triple P pM Q
  ( yout, Entails (Q yout) (Q' y))
    Triple P (Return pM y) Q'.
Proof.
  intros.
  eapply Consequence_post.
  - apply Return_Spec; eauto.
  - setoid_rewrite Entails_iff in . setoid_rewrite Entails_iff. intros ? ? (&(?&?)). eauto.
Qed.


Lemma Return_SpecT (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (k : ) (Q : Assert sig n) (pM : pTM sig n) (y : ) :
  TripleT P k pM Q
  TripleT P k (Return pM y) ( y' t y' = y y'', Q y'' t).
Proof.
  split.
  - apply Return_Spec; eauto.
  - eapply TerminatesIn_monotone.
    + TM_Correct. apply H.
    + firstorder.
Qed.


Lemma Return_SpecT_con (sig : finType) (F1 F2 : finType) (n : ) (P : Assert sig n) (k : ) (Q : Assert sig n) (Q' : Assert sig n) (pM : pTM sig n) (y : ) :
  TripleT P k pM Q
  ( yout, Entails (Q yout) (Q' y))
  TripleT P k (Return pM y) Q'.
Proof.
  intros.
  eapply ConsequenceT_post.
  - apply Return_SpecT; eauto.
  - setoid_rewrite Entails_iff in . setoid_rewrite Entails_iff. intros ? ? (&(?&?)). eauto.
Qed.



Lemma Seq_Spec (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n) :
  Triple P Q
  ( ymid, Triple (Q ymid) R)
  Triple P (;;) R.
Proof.
  intros .
  eapply TripleI, Realise_monotone.
  { TM_Correct. apply .
    instantiate (1 := tin '(yout, tout)
                         (ymid : ),
                          Q ymid tin
                          R yout tout).
    {
      clear P . setoid_rewrite Triple_iff in . unfold Realise in *.
      intros tin k outc HLoop.
      intros ymid Hmid.
      specialize with (1 := HLoop). cbn in *.
      eapply ; eauto.
    }
  }
  {
    intros tin (yout, tout) H. TMSimp.
    intros. modpon H. modpon . eapply .
  }
Qed.


Lemma Seq_Spec' (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n) :
  Triple P ( _ Q)
  (Triple Q R)
  Triple P (;;) R.
Proof. eauto using Seq_Spec. Qed.

Lemma Seq_Spec_swapped (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n) :
  ( ymid, Triple (Q ymid) R)
  Triple P Q
  Triple P (;;) R.
Proof. eauto using Seq_Spec. Qed.

Lemma Seq_Spec_swapped' (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n) :
  (Triple Q R)
  Triple P ( _ Q)
  Triple P (;; ) R.
Proof. eauto using Seq_Spec. Qed.


Lemma Seq_SpecT_strong (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n)
      (k k1 k2 : ) :
  TripleT P Q
  ( (ymid : ), TripleT (Q ymid) R)
  ( tin ymid tmid, P tin Q ymid tmid 1 + + k)
  TripleT P k (;; ) R.
Proof.   intros .
  split.
  - eapply Seq_Spec.
    + apply .
    + cbn. apply .
  - eapply TerminatesIn_monotone.
    {
      apply Seq_TerminatesIn'.       - apply .
      - apply .
      - instantiate (1 := tmid k2' ymid, Q ymid tmid ).
        {
          clear . setoid_rewrite TripleT_iff in . unfold TerminatesIn in *. firstorder.
        }
    }
    {
      clear .
      intros tin k' (HP&Hk). unfold Triple_TRel in *.
      exists . repeat split; eauto.
      unfold Triple_Rel. intros ymid tmid HQ. modpon HQ.
      specialize with (1 := HP) (2 := HQ).
      exists . split; eauto.
      .
    }
Qed.


Lemma Seq_SpecT (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n)
      (k k1 k2 : ) :
  TripleT P Q
  ( (ymid : ), TripleT (Q ymid) R)
  1 + + k
  TripleT P k (;; ) R.
Proof. intros. eapply Seq_SpecT_strong; eauto. Qed.

Lemma Seq_SpecT' (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n)
      (k k1 k2 : ) :
  TripleT P ( _ Q)
  (TripleT Q R)
  1 + + k
  TripleT P k (;;) R.
Proof. eauto using Seq_SpecT. Qed.


Lemma If_Spec (sig : finType) (n : ) (F : finType) (pM1 : pTM sig bool n) (pM2 pM3 : pTM sig F n)
      (P : Assert sig n) (Q : bool Assert sig n) (R : F Assert sig n) :
  Triple P Q
  Triple (Q true) R
  Triple (Q false) R
  Triple P (If ) R.
Proof.
  rewrite !Triple_iff. intros .
  eapply Realise_monotone.
  - TM_Correct; eauto.
  - intros tin (yout, tout) H. cbn in *. firstorder.
Qed.


Lemma If_SpecT (sig : finType) (n : ) (F : finType) (pM1 : pTM sig bool n) (pM2 pM3 : pTM sig F n)
      (P : Assert sig n) (Q : bool Assert sig n) (R : F Assert sig n)
      (k k1 k2 k3 : ) :
  TripleT P Q
  TripleT (Q true) R
  TripleT (Q false) R
  ( tin yout tout, P tin Q yout tout
                    (1 + + if yout then else ) k)
  TripleT P k (If ) R.
Proof.
  intros . split.
  - eapply If_Spec.
    + apply .
    + apply .
    + apply .
  - eapply TerminatesIn_monotone.
    { apply If_TerminatesIn'.       - apply .
      - apply .
      - apply .
      - apply . }
    {
      unfold Triple_Rel, Triple_TRel. intros tin k' (H&Hk).
      specialize with (1 := H).
      exists . repeat split.
      - assumption.
      - reflexivity.
      - intros tmid ymid Hmid. modpon Hmid.
        modpon . destruct ymid; cbn in *.
        + exists . repeat split; auto. .
        + exists . repeat split; auto. .
    }
Qed.


Lemma If_SpecTReg (sig : finType) (n : ) (F : finType) (pM1 : pTM _ bool n) (pM2 pM3 : pTM _ F n)
      (P : Spec sig n) (Q : bool Spec sig n) (R : F Spec sig n)
      (k k1 k2 k3 : ) :
  TripleT ≃≃( P) ( y ≃≃( Q y))
  TripleT ≃≃( Q true) ( y ≃≃( R y))
  TripleT ≃≃( Q false) ( y ≃≃( R y))
  (implList (fst P) ( b, implList (fst (Q b)) (1 + + (if b then else ) k)))
  TripleT ≃≃( P) k (If ) ( y ≃≃( R y)).
Proof.
  intros . eapply If_SpecT. 1-3:eassumption. cbn.
  intros. do 2 setoid_rewrite implList_iff in . specialize with (b:=yout). destruct P,(Q yout). eapply ;cbn. all:eapply tspecE;eauto.
Qed.


Lemma If_SpecT_weak (sig : finType) (n : ) (F : finType) (pM1 : pTM sig bool n) (pM2 pM3 : pTM sig F n)
      (P : Assert sig n) (Q : bool Assert sig n) (R : F Assert sig n)
      (k k1 k2 k3 : ) :
  TripleT P Q
  TripleT (Q true) R
  TripleT (Q false) R
  (1 + + max k)
  TripleT P k (If ) R.
Proof.
  intros. eapply If_SpecT; eauto.
  intros. destruct yout.
  + assert ( max ) by apply Nat.le_max_l. .
  + assert ( max ) by apply Nat.le_max_r. .
Qed.


Lemma If_SpecT_weak' (sig : finType) (n : ) (F : finType) (pM1 : pTM sig bool n) (pM2 pM3 : pTM sig F n)
      (P : Assert sig n) (Q : bool Assert sig n) (R : F Assert sig n)
      (k k1 k2 : ) :
  TripleT P Q
  TripleT (Q true) R
  TripleT (Q false) R
  (1 + + k)
  TripleT P k (If ) R.
Proof.
  intros .
  eapply ConsequenceT_pre.
  - eapply If_SpecT_weak with ( := ) ( := ); eauto.
  - auto.
  - now rewrite Nat.max_id.
Qed.



Lemma Switch_Spec (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n) :
  Triple P Q
  ( (y : ), Triple (Q y) ( y) R)
  Triple P (Switch ) R.
Proof.
  intros .
  eapply TripleI, Realise_monotone.
  - apply Switch_Realise.
    + apply .
    + apply .
  - intros tin (yout, tout) H. cbn in *. firstorder.
Qed.


Lemma Switch_SpecT (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n)
      (k k1 k2 : ) :
  TripleT P Q
  ( (y : ), TripleT (Q y) ( y) R)
  (1 + + k)
  TripleT P k (Switch ) R.
Proof.
  intros .
  split.
  - eapply Switch_Spec.
    + apply .
    + apply .
  - eapply TerminatesIn_monotone.
    + apply Switch_TerminatesIn.
      * apply .
      * apply .
      * apply .
    + unfold Triple_TRel. intros tin k' (H&Hk).
      exists , . repeat split; eauto. .
Qed.


Lemma Switch_SpecT_strong (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM sig n) (pM2 : pTM sig n)
      (P : Assert sig n) (Q : Assert sig n) (R : Assert sig n)
      (k k1 : ) (k2 : ) :
  TripleT P Q
  ( (y : ), TripleT (Q y) ( y) ( y) R)
  ( tin yout tout, P tin Q yout tout 1 + + yout k)
  TripleT P k (Switch ) R.
Proof.
  intros .
  split.
  - eapply Switch_Spec.
    + apply .
    + apply .
  - eapply TerminatesIn_monotone.
    + apply Switch_TerminatesIn'.
      * apply .
      * apply .
      * apply .
    + unfold Triple_TRel. intros tin k' (H&Hk).
      exists . repeat split.
      * assumption.
      * reflexivity.
      * unfold Triple_Rel. intros tmid ymid Hmid. modpon Hmid.
        specialize with (1 := H) (2 := Hmid).
        exists ( ymid). repeat split; eauto. .
Qed.


Lemma Switch_SpecTReg (sig : finType) (n : ) (F1 F2 : finType) (pM1 : pTM _ n) (pM2 : pTM _ n)
     (P : Spec sig n) Q R
      (k k1 : ) (f : ) :
  TripleT ≃≃(P) k ( y ≃≃(Q y))
  ( (y : ), TripleT ≃≃(Q y) (f y) ( y) ( y ≃≃(R y)))
  (implList (fst P) ( y, implList (fst (Q y)) (1 + k + f y )))
  TripleT ≃≃(P) (Switch ) ( y ≃≃(R y)).
Proof.
  intros . eapply Switch_SpecT_strong. 1-2:eassumption.
  intros. destruct P. eapply tspecE in H as []. eapply implListE in . 2:easy.
  setoid_rewrite implList_iff in . apply .
  cbn in . destruct Q. eapply tspecE;eassumption.
Qed.




Lemma While_Spec0 (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM sig (option F) n)
      (P : Assert sig n) (Q : option F Assert sig n) (R : F Assert sig n) :
  Triple P pM Q
  ( yout tout, Q (Some yout) tout R yout tout)
  ( tmid, Q None tmid P tmid)
  Triple P (While pM) R.
Proof.
  intros .
  eapply TripleI, Realise_monotone.
  { TM_Correct. apply . }
  { clear .
    unfold Triple_Rel in *.
    apply WhileInduction; firstorder.
  }
Qed.



Lemma While_Spec (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM sig (option F) n)
      (X : Type)
      (P : X Assert sig n) (Q : X option F Assert sig n) (R : X F Assert sig n) :
  ( x, Triple (P x) pM (Q x))
  ( x yout tmid tout, P x tmid Q x (Some yout) tout R x yout tout)
  ( x tin tmid, P x tin Q x None tmid x', P x' tmid yout tout, R x' yout tout R x yout tout)
   (x : X), Triple (P x) (While pM) (R x).
Proof.
  intros .
  enough (While pM tin '(yout, tout) (x : X), P x tin R x yout tout) as H.
  {
    clear . intros. rewrite Triple_iff. unfold Triple_Rel, Realise in *. eauto.
  }
  {
    eapply Realise_monotone.
    { clear .
      apply While_Realise with (R := tin '(yout, tout) (x : X), P x tin Q x yout tout).
      hnf. setoid_rewrite Triple_iff in . unfold Triple_Rel in *. firstorder. }
    {
      clear . apply WhileInduction; intros.
      - eapply ; eauto.
      - specialize HStar with (1 := H).
        specialize with (1 := H) (2 := HStar) as (x'&&).
        eapply ; eauto.
    }
  }
Qed.


Lemma While_SpecReg (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM _ (option F) n)
      (X : Type)
      (P : X Spec sig n) (Q : X option F Spec sig n) (R : X F Spec sig n) :
  ( x, Triple ≃≃( P x) pM ( y ≃≃( Q x y)))
  ( x , implList (fst (P x))
       ( yout, implList (fst (Q x (Some yout))) (Entails ≃≃( [],snd (Q x (Some yout))) ≃≃( R x yout)))
      (implList (fst (Q x None)) ( x', Entails ≃≃( [],snd (Q x None)) ≃≃( P x')
                                     ( yout, Entails ≃≃( R x' yout) ≃≃( R x yout)))))
   (x : X), Triple ≃≃( P x) (While pM) ( y ≃≃( R x y)).
Proof.
  intros . eapply While_Spec with (1:=).
  - intros ? ? ? ? ?. revert tout. apply EntailsE.
    specialize ( x) as [ ?]. destruct (P x);cbn in *. apply tspecE in H as [H _].
    do 2 setoid_rewrite implList_iff in . specialize ( H yout).
    destruct (Q x (Some yout));cbn in *. eapply tspec_introPure. rewrite implList_iff. eauto.
  - intros **. specialize ( x) as [? ]. destruct (P x);cbn in *.
    apply tspecE in H as [H _]. setoid_rewrite implList_iff in .
    destruct (Q x None);cbn in *.
    eapply tspecE in as (&?). specialize ( ) as (x'&&H'). eexists x'.
    split. {eapply (EntailsE ). eapply tspecI. now hnf. easy. }
    intros ? . now eapply EntailsE.
Qed.


Lemma While_SpecT (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM sig (option F) n)
      (X : Type) (f g : X )
      (P : X Assert sig n) (Q : X option F Assert sig n) (R : X F Assert sig n) :
  ( x, TripleT (P x) (g x) pM (Q x))
  ( x yout tmid tout, P x tmid Q x (Some yout) tout R x yout tout g x f x)
  ( x tin tmid, P x tin Q x None tmid x', P x' tmid 1 + g x + f x' f x yout tout, R x' yout tout R x yout tout)
   (x : X), TripleT (P x) (f x) (While pM) (R x).
Proof.
  intros x.
  split.
  { eapply While_Spec; eauto.
    - intros y yout tmid tout Hp Hq. specialize with (1 := Hp) (2 := Hq). firstorder.
    - intros x' tin tmid Hp Hq. specialize with (1 := Hp) (2 := Hq). firstorder.
  }
  enough ( (While pM) ( tin k x, P x tin f x k)) as H.
  { clear . unfold Triple_TRel, TerminatesIn. firstorder. }
  {
    clear x.     eapply TerminatesIn_monotone.
    {
      clear .       apply While_TerminatesIn with (R := tin '(yout, tout) (x : X), P x tin Q x yout tout)
                                    (T := tin k' (x : X), P x tin g x k').
      - hnf. setoid_rewrite TripleT_iff in . unfold Triple_TRel in *.
        intros tin k' outc HLoop x Hx.
        specialize with (x := x) as (&).
        setoid_rewrite Triple_iff in .
        unfold Triple_Rel, Realise in ; clear .
        firstorder.
      - hnf. setoid_rewrite TripleT_iff in . unfold Triple_TRel in *.
        intros tin k' (x&H&Hk). specialize with (x := x) as (&).
        unfold Triple_TRel, TerminatesIn in ; clear . firstorder.
    }
    {
      clear .       apply WhileCoInduction; intros.
      hnf in HT. destruct HT as (x&HPx&Hk).
      exists (g x). split.
      - exists x. split; eauto.
      - intros [ y | ].
        + clear .           intros tmid H.
          specialize H with (1 := HPx).
          specialize with (1 := HPx) (2 := H) as (&).
          .
        + clear .           intros tmid H.
          specialize H with (1 := HPx).
          specialize with (1 := HPx) (2 := H) as (x'&&).
          exists (f x'). unfold Triple_TRel. repeat split.
          * exists x'. split; [assumption|].
          * .
    }
  }
Qed.


Lemma While_SpecTReg (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM _ (option F) n)
      (X : Type) (f__loop f__step : X )
      (PRE : X Spec sig n) (INV : X option F Spec sig n) (POST : X F Spec sig n) :
  ( x, TripleT ≃≃( PRE x) (f__step x) pM ( y ≃≃( INV x y)))
  ( x , implList (fst (PRE x)) ( yout, implList (fst (INV x (Some yout))) (Entails ≃≃( [],snd (INV x (Some yout))) ≃≃( POST x yout) f__step x f__loop x))
      (implList (fst (INV x None)) ( x', Entails ≃≃( [],snd (INV x None)) ≃≃( PRE x') 1 + f__step x + f__loop x' f__loop x
                                     ( yout, Entails ≃≃( POST x' yout) ≃≃( POST x yout)))))
   (x : X), TripleT ≃≃( PRE x) (f__loop x) (While pM) ( y ≃≃( POST x y)).
Proof.
  intros . eapply While_SpecT with (1:=).
  - intros x y ? ? ? H'.
    specialize ( x) as [ ?]. setoid_rewrite implList_iff in . destruct (PRE _). apply tspecE in H as [H _].
    specialize ( H y).
    destruct (POST x y). destruct (INV x (Some _)). specialize (tspecE H') as [ ?].
    setoid_rewrite implList_iff in . specialize ( ) as []. split. 2:easy. eapply . eapply tspecI. all:easy.
  - intros **. specialize ( x) as [? ]. destruct (PRE _). destruct (INV _ _).
    apply tspecE in H as [H _]. setoid_rewrite implList_iff in .
    eapply tspecE in as (&?). specialize ( ) as (x'&&?&H'). eexists x'.
    split. {eapply (EntailsE ). eapply tspecI. now hnf. easy. }
    split. easy.
    intros ? . now eapply EntailsE.
Qed.


Lemma While_SpecTReg' (sig : finType) (n : ) (F : finType) {inF : inhabitedC F} (pM : pTM _ (option F) n)
      (X : Type) (f g : X )
      P' Q' R' (P : X SpecV sig n) (Q : X option F SpecV sig n) (R : X F SpecV sig n) :
  ( x, TripleT ≃≃( P' x, P x) (g x) pM ( y ≃≃( Q' x y, Q x y)))
  ( x , implList (P' x)
       ( yout, implList (Q' x (Some yout)) (Entails ≃≃( [],Q x (Some yout)) ≃≃( R' x yout,R x yout) g x f x))
      (implList (Q' x None) ( x', Entails ≃≃( [],Q x None) ≃≃( P' x', P x') 1 + g x + f x' f x
                                     ( yout, Entails ≃≃( R' x' yout,R x' yout) ≃≃( R' x yout,R x yout)))))
   (x : X), TripleT ≃≃( P' x,P x) (f x) (While pM) ( y ≃≃( R' x y,R x y)).
Proof.
  intros . eapply While_SpecTReg with (INV := _ _ (_,_)). all:easy.
Qed.