Module PedraZ

This module offers an abstract domain of polyhedra which takes as inputs linear integer expressions (LinExpr.ZExpr).

Require String.
Require Import ZNoneItv.
Require Import Itv.
Require Import ASAtomicCond.
Require Import PedraQ.
Require Import AssignD.
Import ZCond.

Module BasicD.

  Definition t:= BasicD.t.

  Definition gamma (a:t) m
    := BasicD.gamma a (Mem.lift ZtoQ.ofZ m).

   Instance gamma_ext: Proper (Logic.eq ==> pointwise_relation PVar.t Logic.eq ==> iff) gamma.
Proof.
     unfold gamma.
     intros x y H m1 m2 H0. subst; rewrite H0; tauto.
   Qed.

  Definition isIncl:=BasicD.isIncl.
  Global Opaque BasicD.isIncl.

  Lemma isIncl_correct: forall a1 a2, If isIncl a1 a2 THEN forall m, gamma a1 m -> gamma a2 m.
Proof.
    unfold gamma. VPLAsimplify.
  Qed.

  Definition top:= BasicD.top.

  Lemma top_correct: forall m, gamma top m.
    simpl; auto.
  Qed.
  Hint Resolve top_correct: vpl.

  Definition bottom: t := BasicD.bottom.

  Lemma bottom_correct: forall m, ~(gamma bottom m).
Proof.
    simpl; auto.
  Qed.

  Definition isBottom : t -> imp bool
    := fun p => BasicD.isBottom p.

  Lemma isBottom_correct : forall a, If isBottom a THEN forall m, gamma a m -> False.
Proof.
    unfold isBottom.
    unfold gamma.
    VPLAsimplify.
    intro.
    eapply (BasicD.isBottom_correct a true Hexta).
  Qed.

  Definition widen:= BasicD.widen.

  Definition join:= BasicD.join.

  Lemma join_correct a1 a2: WHEN p <- join a1 a2 THEN forall m, gamma a1 m \/ gamma a2 m -> gamma p m.
Proof.
    unfold gamma; VPLAsimplify.
  Qed.

  Definition project (a:t) (x:PVar.t) : imp t :=
    BasicD.project a x.

  Lemma project_correct: forall a x, WHEN p <- project a x THEN forall m v, gamma a m -> gamma p (Mem.assign x v m).
Proof.
    unfold gamma. VPLAsimplify.
    simpl. intros; autorewrite with vpl; auto.
  Qed.

  Definition rename (x y: PVar.t) (a:t): imp t :=
    Rename.rename x y a.

  Lemma rename_correct: forall x y a, WHEN p <- (rename x y a) THEN
    forall m, gamma a (Mem.assign x (m y) m) -> gamma p m.
Proof.
    unfold gamma. VPLAsimplify.
    simpl; intros H m; autorewrite with vpl; auto.
  Qed.

  Definition pr: t -> String.string
    := fun ab => BasicD.pr ab.

  Import LinTerm.
  Import String.
  Definition get_itv_msg :="get_itv: non-affine term "%string.

  Definition get_itv: ZTerm.t -> t -> imp ZItv.t
    := fun a ab =>
     let (te,aft) := ZTerm.affineDecompose a in
     if ZTerm.pseudoIsZero te then
       BIND qitv <- ItvD.getItv ab (LinQ.lift (ZAffTerm.lin aft)) -;
          pure (proj1_sig (ZItv.fromQItv (QItv.shift qitv (ZtoQ.ofZ (ZAffTerm.cte aft)))))
     else
          pure (trace DEBUG (get_itv_msg ++ (ZTerm.pr a)) (projT1 (ZItv.mk ZItv.Infty ZItv.Infty))).

  Import ZNum.

  Lemma get_itv_correct t a:
    WHEN i <- get_itv t a THEN forall m, gamma a m -> ZItv.sat i (ZTerm.eval t m).
Proof.
    unfold get_itv.
    xasimplify ltac: (eauto with pedraQ vpl). simpl in * |- *.
    intros m X. apply (proj2_sig (ZItv.fromQItv _)).
    generalize (ZTerm.affineDecompose_correct t m).
    rewrite H. intros X0; ring_simplify in X0. rewrite <- X0.
    unfold ZAffTerm.eval; autorewrite with num.
    rewrite QNum.AddComm.
    apply QItv.Shift_correct.
    rewrite <- LinQ.lift_correct.
    auto.
  Qed.

End BasicD.


Module ZNItvD <: HasGetItvMode ZNum ZTerm ZNoneItv.ZNItv BasicD.

  Import LinTerm.
  Import ZNItv.
  Import BasicD.

  Definition getItvMode mo te a :=
     let (te,aft) := ZTerm.affineDecompose te in
     if ZTerm.pseudoIsZero te then
          BIND qitv <- ItvD.getItvMode mo (LinQ.lift (ZAffTerm.lin aft)) a -;
          pure (add BOTH (fromQItv qitv) (single (ZAffTerm.cte aft)))
     else
          pure (failwith "get_itv: non-affine term" ZNItv.top).
  Extraction Inline getItvMode.

  Local Opaque ZNItv.add.
  Import ZNum.

  Lemma getItvMode_correct mo t a:
    WHEN i <- getItvMode mo t a THEN forall m, gamma a m -> ZNItv.sat i (ZTerm.eval t m).
Proof.
    unfold getItvMode.
    xasimplify ltac: (eauto with pedraQ vpl zn). simpl in * |- *.
    intros m X.
    generalize (ZTerm.affineDecompose_correct t m).
    rewrite H. intros X0; ring_simplify in X0. rewrite <- X0.
    unfold ZAffTerm.eval; autorewrite with num.
    apply add_correct; auto with zn.
    apply fromQItv_correct.
    rewrite <- LinQ.lift_correct.
    auto.
  Qed.
  Global Hint Resolve getItvMode_correct: vpl.
  Opaque getItvMode.

End ZNItvD.

Module CstrD <: HasAssume ZNum ZtoQCstr BasicD.

  Import BasicD.

  Definition assume (c:ZtoQCstr.t) (a:t) : imp t :=
    CstrD.assume c a.
  
  Lemma assume_correct: forall c a, WHEN p <- assume c a THEN forall m, ZtoQCstr.sat c m -> gamma a m -> gamma p m.
Proof.
    unfold gamma. VPLAsimplify.
  Qed.


End CstrD.

Module AtomicD := BasicD <+ ZAtomicCondAssume BasicD CstrD ZNItvD.

Module Dom <: AbstractDomain ZNum ZCond
  := BasicD <+ ZCondAssume BasicD AtomicD <+ ASCondAssert ZNum ZCond.

Module FullDom <: FullItvAbstractDomain ZNum ZCond ZItv
  := MakeAssign ZNum ZCond Dom Dom <+ AssignLiftItv ZNum ZCond ZItv Dom Dom Dom
                                   <+ AssignSimplePrinting ZNum ZCond Dom Dom Dom
  .