Library Scat.KernelVCG

VCG of kernel programs


Require Import Assertions.
Require Import Guassign.
Require Import Atoms.
Require Import BoundedIteration.
Require Export Kernel.

Frames of programs

Frame bound for atoms
Definition atbounds (bound: positive) (p: atom): Prop :=
  match p with
 | guassign l clbounds bound l cbounds bound c
 | skipTrue
 | xrequire c _cbounds bound c
 | ensure ccbounds bound c
 | assign x tcbounds bound (ceq x t)
 end.

Lemma atbounds_Zle p bound1:
   atbounds bound1 p bound2:positive, (Zpos bound1) (Zpos bound2)atbounds bound2 p.
Proof.
  case p; simpl; intuition eauto with echecker echecker2.
Qed.

Hint Resolve atbounds_Zle: echecker.

Definition atbound (p: atom) (bound: positive): positive :=
  match p with
 | guassign l clbound l (cbound c bound)
 | skipbound
 | xrequire c _cbound c bound
 | ensure ccbound c bound
 | assign x tcbound (ceq x t) bound
 end.

Lemma atbound_monotonic p: bound, (Zpos bound) Zpos (atbound p bound).
Proof.
  case p; simpl; intros; auto with checker.
  eapply Zle_trans.
  2: eapply lbound_monotonic.
  auto with checker.
  eapply Zle_trans.
  2: eapply Zle_Pmax_l.
  auto with checker.
Qed.

Hint Resolve atbound_monotonic: checker.

Lemma atbound_atbounds p: bound, (atbounds (atbound p bound) p).
Proof.
  induction p; simpl; intuition eauto with checker echecker echecker2.
Qed.

Hint Resolve atbound_atbounds: checker.

Frame bound for kernel
Fixpoint Kbounds (bound: positive) (p: kernel): Prop :=
  match p with
 | Kle_iter _ _ body last nextKbounds bound body Kbounds bound last Kbounds bound next
 | Kgjoin min max pf z, min z maxKbounds bound (pf z)
 | Kiat instatbounds bound inst
 | Kseq pf pnKbounds bound pf Kbounds bound pn
 | Kjoin pl prKbounds bound pl Kbounds bound pr
 | Kjoinch pl pr aKbounds bound pl Kbounds bound pr abounds bound a
 | Kloop body aKbounds bound body abounds bound a
 | Kclone x bodytbounds bound x Kbounds bound body
 | Kdeflabel _ _ pKbounds bound p
 | Kbranch2 _ pKbounds bound (p true) Kbounds bound (p false)
 | Kbranch l p z, (labmin l) z (labmax l)Kbounds bound (p z)
 end.

Opaque tbounds.

Lemma Kbounds_Zle p bound1:
   Kbounds bound1 p bound2:positive, (Zpos bound1) (Zpos bound2)Kbounds bound2 p.
Proof.
  induction p; simpl; intuition eauto with echecker.
Qed.

Hint Resolve Kbounds_Zle: echecker.

Fixpoint Kbound (p: kernel) (bound: positive): positive :=
  match p with
 | Kle_iter _ _ body last nextKbound body (Kbound last (Kbound next bound))
 | Kgjoin min max pfbiter min max (fun zKbound (pf z)) bound
 | Kiat instatbound inst bound
 | Kseq pf pnKbound pf (Kbound pn bound)
 | Kjoin pl prKbound pl (Kbound pr bound)
 | Kjoinch pl pr aKbound pl (Kbound pr (abound a bound))
 | Kloop body aKbound body (abound a bound)
 | Kclone x bodytbound x (Kbound body bound)
 | Kdeflabel _ _ pKbound p bound
 | Kbranch2 _ pKbound (p true) (Kbound (p false) bound)
 | Kbranch l pbiter (labmin l) (labmax l) (fun zKbound (p z)) bound
 end.

Opaque tbound.

Lemma Kbound_monotonic p: bound, (Zpos bound) Zpos (Kbound p bound).
Proof.
  induction p; simpl; intros; auto with checker;
  try (eapply Zle_trans; [ idtac | eauto ]; auto with checker; fail).
  eapply Zle_trans.
  2: eauto.
  eapply Zle_trans.
  2: eauto.
  eapply Zle_trans.
  2: eauto.
  eauto with checker.
  biter_ind.
  intros; omega.
  intros; generalize (H n x); omega.
  eapply Zle_trans.
  2: eauto.
  eapply Zle_trans.
  2: eauto.
  eauto with checker.
  biter_ind.
  intros; omega.
  intros; generalize (H n x); omega.
Qed.

Hint Resolve Kbound_monotonic: checker.

Lemma Kbound_Kbounds p: bound, (Kbounds (Kbound p bound) p).
Proof.
  induction p; simpl; do_except_on @biter ltac:(intuition eauto with checker echecker).
  intros bound z; biter_ind.
  intros n x H0 H1 H2.
  biter_split_le H2.
  intros; eapply Kbounds_Zle.
  eapply H1.
  omega.
  auto with checker.
  intros bound z; biter_ind.
  intros n x H0 H1 H2.
  biter_split_le H2.
  intros; eapply Kbounds_Zle.
  eapply H1.
  omega.
  auto with checker.
Qed.

Transparent tbound tbounds.

Hint Resolve Kbound_Kbounds: checker.

Definition bound p := Kbound p 1.

Theorem bound_Kbounds p: Kbounds (bound p) p.
Proof.
  unfold bound; auto with checker.
Qed.

VCG code

trace = origin of VCs
Inductive trace: Type :=
  | Req (c:cond) (m: string) | LoopPre | LoopPost | Unchecked_Union.

Operators used by our VCG
Module Type VCGparameters.

  Parameter tauto: cond.
  Parameter absurd: cond.
  Parameter hard_and: condcondcond.
  Parameter ceq: vartermcond.

  Parameter trename: termpositivepositiveterm.

  Parameter rename: condpositivepositivecond.

A Writer Monad for collecting result of checker. Typically :
  • a error monad (when a inclusion test fails).
  • a state monad with state = a list of undischarged VC.
   Parameter monad: TypeType.

   Parameter ret: {A}, Amonad A.

   Parameter bind: {A B}, (monad A) → (Amonad B) → monad B.

check_entails mesg pre post k means that computation k is guarded by inclusion test pre post and mesg gives info on the origin of the inclusion test.
   Parameter check_entails: {A}, tracepositivecondcond → (monad A) → (monad A).

soft_or c1 c2 typically calls an external untrusted tool to compute c = c1 c2 but "check" c1 c and c2 c. May generate some VC and returns c.
   Parameter soft_or: positivecondcondmonad cond.


Some notations in order to have a more readable code

  Bind Scope VCG_scope with monad.

  Notation "'do' x <- p1 ';' p2" := (bind p1 (fun xp2))
    (at level 95, p1 at level 93, right associativity): VCG_scope.


  Notation "{ mesg # n # c1 |= c2 } k" := (check_entails mesg n c1 c2 k)
    (at level 95, right associativity): VCG_scope.

End VCGparameters.

Module GenericVCG(Arg: VCGparameters).

Export Arg.

Record postfinder_result (A:Type): Type := {
   pbnd: positive ;
   post: A
}.
Implicit Arguments pbnd [A].
Implicit Arguments post [A].
Implicit Arguments Build_postfinder_result [A].

Section VCGCode.

Open Scope VCG_scope.

Let xret := fun {A} ⇒ ret (A:=postfinder_result A).
Coercion xret: postfinder_result >-> monad.

Definition atpostfinder (p: atom) (pre: cond) (cour: positive): monad (postfinder_result cond) :=
 match p with
 | guassign l c
     let r:=lfresh l cour in
     {| pbnd:=rbound r ; post:=hard_and (rsubst pre r) (orsubst c r) |}
 | skip
    {| pbnd:=cour ; post:=pre |}
 | xrequire c m
     { Req c m # cour # pre |= c }
     {| pbnd:=cour ; post:=pre |}
 | ensure c
     {| pbnd:=cour ; post:=hard_and pre c |}
 | assign x t
     {| pbnd:=(cour+1)%positive ; post:=hard_and (ceq x (trename t (vid x) cour)) (rename pre (vid x) cour) |}
 end.

Fixpoint postfinder_le_iter (n:nat) (ol:option alabel) (body next: condpositiveaenvironmentmonad (postfinder_result cond))
   (pre: cond) (cour: positive) (aenv: aenvironment) (zof_n: Z): monad (postfinder_result (cond × (postfinder_result cond))) :=
 match n with
 | Odo res <- next pre cour (oadd ol pre 0 aenv) ;
         {| pbnd := cour ; post := (pre, res) |}
 | S ndo aux <- postfinder_le_iter n ol body next pre cour aenv (zof_n-1) ;
          let post1 := fst (post aux) in
          let res1 := snd (post aux) in
          do res2 <- body post1 (pbnd aux) (oadd ol post1 zof_n aenv) ;
          do res3 <- next (post res2) (pbnd res2) (oadd ol (post res2) zof_n aenv) ;
          {| pbnd := pbnd res2 ;
             post := (post res2,
                      {| pbnd := Pmax (pbnd res1) (pbnd res3) ; post := bin OR (post res1) (post res3) |})
          |}
 end.

Definition internal_error := xrequire absurd "internal error".

Fixpoint postfinder (p: kernel) (pre: cond) (cour: positive) (aenv: aenvironment): monad (postfinder_result cond) :=

  match p with
  | Kle_iter n ol body last next
     let zof_n:=(Z_of_nat n) in
     let succ_zof_n:=zof_n+1 in
     do aux <- postfinder_le_iter n ol (postfinder body) (postfinder next) pre cour aenv zof_n ;
     let post1 := fst (post aux) in
     let res1 := snd (post aux) in
     do res2 <- postfinder body post1 (pbnd aux) (oadd ol post1 succ_zof_n aenv) ;
     do res3 <- postfinder last (post res2) (pbnd res2) (oadd ol (post res2) succ_zof_n aenv) ;
     {| pbnd := Pmax (pbnd res1) (pbnd res3) ; post := bin OR (post res1) (post res3)|}
   | Kgjoin min max pf
     biter min max (fun z Kdo aux1 <- K ;
                               do aux2 <- postfinder (pf z) pre cour aenv ;
                               {| pbnd := Pmax (pbnd aux1) (pbnd aux2) ; post := bin OR (post aux1) (post aux2) |})
                    {| pbnd := cour ; post := absurd |}
  | Kiat instatpostfinder inst pre cour
  | Kseq pf pn
     do resf <- postfinder pf pre cour aenv ;
     postfinder pn (post resf) (pbnd resf) aenv
  | Kjoin pl pr
     do resl <- postfinder pl pre cour aenv ;
     do resr <- postfinder pr pre cour aenv ;
     let cour := Pmax (pbnd resl) (pbnd resr) in
     do res <- soft_or cour (post resl) (post resr) ;
     {| pbnd := cour ; post := res |}
  | Kjoinch pl pr a
     let convexhull := aeval a aenv in
     do resl <- postfinder pl pre cour aenv ;
     do resr <- postfinder pr pre cour aenv ;
     let cour0 := Pmax (pbnd resl) (pbnd resr) in
     { Unchecked_Union # cour0 # post resl |= convexhull }
     { Unchecked_Union # cour0 # post resr |= convexhull }
     {| pbnd := cour ; post := convexhull |}
  | Kloop body a
     let inv := aeval a aenv in
     do res <- postfinder body inv cour aenv ;
     { LoopPre # pbnd res # pre |= inv }
     { LoopPost # pbnd res # post res |= inv }
     {| pbnd := cour ; post := inv |}
  | Kclone x body
    let old:=(mkvar (vtag x) cour) in
    do res <- postfinder body (hard_and (ceq x old) (rename pre (vid x) cour)) (cour+1)%positive aenv ;
    let rb := pbnd res in
    {| pbnd := rb ; post := rsubst (post res) (swap x old rb) |}
  | Kdeflabel l x ppostfinder p pre cour (aadd (labid l) {| acond := pre ; abranch := x |} aenv)
  | Kbranch2 l ppostfinder (p (Zeq_bool (abranch (afind (labid l) aenv)) (labmin l))) pre cour aenv
  | Kbranch l psafe_branch l aenv (fun zpostfinder (p z) pre cour aenv)
                                      (atpostfinder internal_error pre cour)
end.

Let void := (Arg.ret tt).

Definition Kvcgen (p: kernel): monad unit :=
  do res <- postfinder p tauto (bound p) aempty ;
  void.

End VCGCode.


End GenericVCG.

Open Scope list_scope.

Instantiation of VCG parameters
Module ConcreteCondWrapper.

  Definition tauto := tauto.
  Definition absurd := absurd.

  Definition hard_and := bin AND.

  Definition trename := trename.
  Definition rename := rename.

  Definition ceq := ceq.

  Record VC : Type := {
        mesg: trace ;
        tbnd: positive ;
        hyp: cond ;
        goal: cond
  }.

  Record result {A}: Type := {
        vcl: list VC;
        value: A
  }.

  Definition monad := fun Alist VCresult (A:=A).

  Definition ret {A} (value: A) : monad A
   := fun l ⇒ {| vcl := l ; value := value |}.

  Definition bind {A B} (k1: monad A) (k2: Amonad B) : monad B
    := fun llet res := k1 l in
             k2 (value res) (vcl res).

  Definition check_entails {A} (mesg:trace) (bound: positive) (p q: cond) (k:monad A): monad A
    := fun lk ({| mesg:=mesg ;
                      tbnd:=bound ;
                      hyp:=p ;
                      goal:=q |}::l).

  Definition soft_or := fun (bound: positive) (c1 c2:cond) ⇒
      (ret (bin OR c1 c2)).

End ConcreteCondWrapper.

Module KVCG := GenericVCG(ConcreteCondWrapper).
Export KVCG.

Fixpoint vc_eval (l: list VC): Prop :=
  match l with
  | vc::l( s, eval (hyp vc) seval (goal vc) s) (vc_eval l)
  | nilTrue
  end.