Lecture notes 20190604

More Semantics 5 Separation 1

Require Import Coq.Relations.Relation_Operators.
Require Import Coq.Relations.Relation_Definitions.
Require Export Coq.ZArith.ZArith.
Require Export Coq.Strings.String.
Require Export Coq.Logic.Classical.

Arguments clos_refl_trans {A} _ _ _.
Arguments clos_refl_trans_1n {A} _ _ _.
Arguments clos_refl_trans_n1 {A} _ _ _.

Open Scope Z.

Review


Definition var: Type := nat.

Inductive aexp : Type :=
  | ANum (n : Z)
  | AId (X : var)
  | APlus (a1 a2 : aexp)
  | AMinus (a1 a2 : aexp)
  | AMult (a1 a2 : aexp)
  | ADeref (a1: aexp) (* <-- new *)
  | AAddr (a1: aexp). (* <-- new *)

Inductive bexp : Type :=
  | BTrue
  | BFalse
  | BEq (a1 a2 : aexp)
  | BLe (a1 a2 : aexp)
  | BNot (b : bexp)
  | BAnd (b1 b2 : bexp).

Inductive com : Type :=
  | CSkip
  | CAss (a1 a2 : aexp) (* <-- new *)
  | CSeq (c1 c2 : com)
  | CIf (b : bexp) (c1 c2 : com)
  | CWhile (b : bexp) (c : com).

Definition var2addr (X: var): Z := Z.of_nat X + 1.

Definition state: Type := Zoption Z.

Inductive aevalR : aexpstateZProp :=
  | E_ANum n st:
      aevalR (ANum n) st n
  | E_AId X st n:
      st (var2addr X) = Some n
      aevalR (AId X) st n
  | E_APlus (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2) :
      aevalR (APlus e1 e2) st (n1 + n2)
  | E_AMinus (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2) :
      aevalR (AMinus e1 e2) st (n1 - n2)
  | E_AMult (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2) :
      aevalR (AMult e1 e2) st (n1 * n2)
  | E_ADeref (e1: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : st n1 = Some n2) :
      aevalR (ADeref e1) st n2
  | E_AAddre (e1: aexp) (n1: Z) st
      (H1 : aevalL e1 st n1):
      aevalR (AAddr e1) st n1
with aevalL : aexpstateZProp :=
  | EL_AId X st:
      aevalL (AId X) st (var2addr X)
  | EL_ADeref (e1: aexp) (n1: Z) st
      (H1 : aevalR e1 st n1) :
      aevalL (ADeref e1) st n1.

Inductive beval : bexpstateboolProp :=
  | E_BTrue st:
      beval BTrue st true
  | E_BFalse st:
      beval BFalse st false
  | E_BEqTrue (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2)
      (H3 : n1 = n2) :
      beval (BEq e1 e2) st true
  | E_BEqFalse (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2)
      (H3 : n1n2) :
      beval (BEq e1 e2) st false
  | E_BLeTrue (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2)
      (H3 : n1 < n2) :
      beval (BLe e1 e2) st true
  | E_BLeFalse (e1 e2: aexp) (n1 n2: Z) st
      (H1 : aevalR e1 st n1)
      (H2 : aevalR e2 st n2)
      (H3 : n1n2) :
      beval (BLe e1 e2) st false
  | E_BNot (e: bexp) (b: bool) st
      (H1 : beval e st b):
      beval (BNot e) st (negb b)
  | E_BAnd (e1 e2: bexp) (b1 b2: bool) st
      (H1 : beval e1 st b1)
      (H2 : beval e2 st b2):
      beval (BAnd e1 e2) st (andb b1 b2).

Module Example.
The following statements are all straightforward if you know a little bit about C programming. The point here is not to persuad yourself that they are correct. It is rather important to see that we can formally prove them under our definitions above. We suppose that X and Y are variable 0 and 1.
Definition X := 0%nat.
Definition Y := 1%nat.
Suppose st is a program state such that the values stored on X and Y are 100 and 99. Also, we assume that the value stored on address 99 and 100 are both 0, and 0 is a null address.
Parameter st: state.
Hypothesis stX: st (var2addr X) = Some 100.
Hypothesis stY: st (var2addr Y) = Some 99.
Hypothesis st99: st 99 = Some 0.
Hypothesis st100: st 100 = Some 0.
Hypothesis st0: st 0 = None.
Here are two basic statements.
Fact ex1: aevalR (AId X) st 100.
Proof. apply E_AId. apply stX. Qed.

Fact ex2: aevalR (AId Y) st 99.
Proof. apply E_AId. apply stY. Qed.
The following statements talk about X and Y's address.
Fact ex3: aevalL (AId X) st 1.
Proof. apply EL_AId. Qed.

Fact ex4: aevalL (AId Y) st 2.
Proof. apply EL_AId. Qed.

Fact ex5: aevalR (AAddr (AId X)) st 1.
Proof. apply E_AAddre. apply EL_AId. Qed.

Fact ex6: aevalR (AAddr (AId Y)) st 2.
Proof. apply E_AAddre. apply EL_AId. Qed.
We can also use the values stored in X and Y as addresses.
Fact ex7: aevalR (ADeref (AId X)) st 0. (* The value of expreesion * X. *)
Proof. eapply E_ADeref. apply E_AId. apply stX. apply st100. Qed.

Fact ex8: aevalR (ADeref (AId Y)) st 0. (* The value of expreesion * Y. *)
Proof. eapply E_ADeref. apply E_AId. apply stY. apply st99. Qed.
It is not too weird to talk about dereference of dereference.
Fact ex9: v, ¬aevalR (ADeref (ADeref (AId X))) st v.
(* The value of expreesion * * X. *)
Proof.
  unfold not.
  intros.
  inversion H; subst.
  inversion H0; subst.
  inversion H3; subst.
  rewrite stX in H5.
  injection H5 as ?.
  subst n0.
  rewrite st100 in H4.
  injection H4 as ?.
  subst n1.
  rewrite st0 in H2.
  discriminate H2.
Qed.

End Example.

Programs' Denotations

The interesting cases below are about assignment commands. Specifically, an assignment command may fail in 3 different way: l-value evaluation fails; rvalue evaluation fails; the address to write is not available.
Inductive ceval : comstateoption stateProp :=
  | E_Skip st:
      ceval CSkip st (Some st)
  | E_AssSucc st1 st2 E E' n n' (* <-- new *)
      (H1: aevalL E st1 n)
      (H2: aevalR E' st1 n')
      (H3: st1 nNone)
      (H4: st2 n = Some n')
      (H5: n'', nn''st1 n'' = st2 n''):
      ceval (CAss E E') st1 (Some st2)
  | E_AssFail1 st1 E E' (* <-- new *)
      (H1: n, ¬aevalL E st1 n):
      ceval (CAss E E') st1 None
  | E_AssFail2 st1 E E' (* <-- new *)
      (H1: n', ¬aevalR E' st1 n'):
      ceval (CAss E E') st1 None
  | E_AssFail3 st1 E E' n (* <-- new *)
      (H1: aevalL E st1 n)
      (H2: st1 n = None):
      ceval (CAss E E') st1 None
  | E_SeqSafe c1 c2 st st' o
      (H1: ceval c1 st (Some st'))
      (H2: ceval c2 st' o):
      ceval (CSeq c1 c2) st o
  | E_SeqCrush c1 c2 st
      (H1: ceval c1 st None):
      ceval (CSeq c1 c2) st None
  | E_IfTrue st o b c1 c2
      (H1: beval b st true)
      (H2: ceval c1 st o):
      ceval (CIf b c1 c2) st o
  | E_IfFalse st o b c1 c2
      (H1: beval b st false)
      (H2: ceval c2 st o):
      ceval (CIf b c1 c2) st o
  | E_IfFail st b c1 c2
      (H1: ¬beval b st true)
      (H2: ¬beval b st false):
      ceval (CIf b c1 c2) st None
  | E_WhileFalse b st c
      (H1: beval b st false):
      ceval (CWhile b c) st (Some st)
  | E_WhileTrue st o b c
      (H1: beval b st true)
      (H2: ceval (CSeq c (CWhile b c)) st o):
      ceval (CWhile b c) st o
  | E_WhileFail st b c
      (H1: ¬beval b st true)
      (H2: ¬beval b st false):
      ceval (CWhile b c) st None.

Small Step Semantics for Expression Evaluation


Inductive aexp_halt: aexpProp :=
  | AH_num : n, aexp_halt (ANum n).

Inductive astepR : stateaexpaexpProp :=
  | ASR_Id : st X n,
      st (var2addr X) = Some n
      astepR st
        (AId X) (ANum n)

  | ASR_Plus1 : st a1 a1' a2,
      astepR st
        a1 a1'
      astepR st
        (APlus a1 a2) (APlus a1' a2)
  | ASR_Plus2 : st a1 a2 a2',
      aexp_halt a1
      astepR st
        a2 a2'
      astepR st
        (APlus a1 a2) (APlus a1 a2')
  | ASR_Plus : st n1 n2,
      astepR st
        (APlus (ANum n1) (ANum n2)) (ANum (n1 + n2))

  | ASR_Minus1 : st a1 a1' a2,
      astepR st
        a1 a1'
      astepR st
        (AMinus a1 a2) (AMinus a1' a2)
  | ASR_Minus2 : st a1 a2 a2',
      aexp_halt a1
      astepR st
        a2 a2'
      astepR st
        (AMinus a1 a2) (AMinus a1 a2')
  | ASR_Minus : st n1 n2,
      astepR st
        (AMinus (ANum n1) (ANum n2)) (ANum (n1 - n2))

  | ASR_Mult1 : st a1 a1' a2,
      astepR st
        a1 a1'
      astepR st
        (AMult a1 a2) (AMult a1' a2)
  | ASR_Mult2 : st a1 a2 a2',
      aexp_halt a1
      astepR st
        a2 a2'
      astepR st
        (AMult a1 a2) (AMult a1 a2')
  | ASR_Mult : st n1 n2,
      astepR st
        (AMult (ANum n1) (ANum n2)) (ANum (n1 * n2))

  | ASR_DerefStep : st a1 a1',
      astepR st
        a1 a1'
      astepR st
        (ADeref a1) (ADeref a1')
  | ASR_Deref : st n n',
      st n = Some n'
      astepR st
        (ADeref (ANum n)) (ANum n')

  | ASR_AddrStep : st a1 a1',
      astepL st
        a1 a1'
      astepR st
        (AAddr a1) (AAddr a1')
  | ASR_Addr : st n,
      astepR st
        (AAddr (ADeref (ANum n))) (ANum n)
with astepL : stateaexpaexpProp :=
  | ASL_Id: st X,
      astepL st
        (AId X) (ADeref (ANum (var2addr X)))

  | ASL_DerefStep: st a1 a1',
      astepR st
        a1 a1'
      astepL st
        (ADeref a1) (ADeref a1')
.

Inductive bstep : statebexpbexpProp :=

  | BS_Eq1 : st a1 a1' a2,
      astepR st
        a1 a1'
      bstep st
        (BEq a1 a2) (BEq a1' a2)
  | BS_Eq2 : st a1 a2 a2',
      aexp_halt a1
      astepR st
        a2 a2'
      bstep st
        (BEq a1 a2) (BEq a1 a2')
  | BS_Eq_True : st n1 n2,
      n1 = n2
      bstep st
        (BEq (ANum n1) (ANum n2)) BTrue
  | BS_Eq_False : st n1 n2,
      n1n2
      bstep st
        (BEq (ANum n1) (ANum n2)) BFalse


  | BS_Le1 : st a1 a1' a2,
      astepR st
        a1 a1'
      bstep st
        (BLe a1 a2) (BLe a1' a2)
  | BS_Le2 : st a1 a2 a2',
      aexp_halt a1
      astepR st
        a2 a2'
      bstep st
        (BLe a1 a2) (BLe a1 a2')
  | BS_Le_True : st n1 n2,
      n1n2
      bstep st
        (BLe (ANum n1) (ANum n2)) BTrue
  | BS_Le_False : st n1 n2,
      n1 > n2
      bstep st
        (BLe (ANum n1) (ANum n2)) BFalse

  | BS_NotStep : st b1 b1',
      bstep st
        b1 b1'
      bstep st
        (BNot b1) (BNot b1')
  | BS_NotTrue : st,
      bstep st
        (BNot BTrue) BFalse
  | BS_NotFalse : st,
      bstep st
        (BNot BFalse) BTrue

  | BS_AndStep : st b1 b1' b2,
      bstep st
        b1 b1'
      bstep st
       (BAnd b1 b2) (BAnd b1' b2)
  | BS_AndTrue : st b,
      bstep st
       (BAnd BTrue b) b
  | BS_AndFalse : st b,
      bstep st
       (BAnd BFalse b) BFalse.

Small Step Semantics for Program Execution


Inductive cstep : (com * state) → (com * state) → Prop :=
  | CS_AssStep1 st E1 E1' E2 (* <-- new *)
      (H1: astepL st E1 E1'):
      cstep (CAss E1 E2, st) (CAss E1' E2, st)
  | CS_AssStep2 st n E2 E2' (* <-- new *)
      (H1: astepR st E2 E2'):
      cstep (CAss (ADeref (ANum n)) E2, st) (CAss (ADeref (ANum n)) E2', st)
  | CS_Ass st1 st2 n1 n2 (* <-- new *)
      (H1: st1 n1None)
      (H2: st2 n1 = Some n2)
      (H3: n, n1nst1 n = st2 n):
      cstep (CAss (ADeref (ANum n1)) (ANum n2), st1) (CSkip, st2)
  | CS_SeqStep st c1 c1' st' c2
      (H1: cstep (c1, st) (c1', st')):
      cstep (CSeq c1 c2 , st) (CSeq c1' c2, st')
  | CS_Seq st c2:
      cstep (CSeq CSkip c2, st) (c2, st)
  | CS_IfStep st b b' c1 c2
      (H1: bstep st b b'):
      cstep (CIf b c1 c2, st) (CIf b' c1 c2, st)
  | CS_IfTrue st c1 c2:
      cstep (CIf BTrue c1 c2, st) (c1, st)
  | CS_IfFalse st c1 c2:
      cstep (CIf BFalse c1 c2, st) (c2, st)
  | CS_While st b c:
      cstep
        (CWhile b c, st)
        (CIf b (CSeq c (CWhile b c)) CSkip, st).

Advanced: Separation Logic

Now, we start to set up the assertion language for defining a Hoare logic.
Module Separation_logic.

Definition logical_var: Type := nat.

Inductive aexp' : Type :=
  | ANum' (t : term)
  | AId' (X: var)
  | APlus' (a1 a2 : aexp')
  | AMinus' (a1 a2 : aexp')
  | AMult' (a1 a2 : aexp')
  | ADeref' (a1: aexp') (* <-- new *)
  | AAddr' (a1: aexp') (* <-- new *)
with term : Type :=
  | TNum (n : Z)
  | TId (x: logical_var)
  | TDenote (a : aexp')
  | TPlus (t1 t2 : term)
  | TMinus (t1 t2 : term)
  | TMult (t1 t2 : term).

Inductive bexp' : Type :=
  | BTrue'
  | BFalse'
  | BEq' (a1 a2 : aexp')
  | BLe' (a1 a2 : aexp')
  | BNot' (b : bexp')
  | BAnd' (b1 b2 : bexp').

Coercion ANum' : term >-> aexp'.
Coercion AId' : var >-> aexp'.
Bind Scope vimp_scope with aexp'.
Bind Scope vimp_scope with bexp'.
Delimit Scope vimp_scope with vimp.

Notation "x + y" := (APlus' x y) (at level 50, left associativity) : vimp_scope.
Notation "x - y" := (AMinus' x y) (at level 50, left associativity) : vimp_scope.
Notation "x * y" := (AMult' x y) (at level 40, left associativity) : vimp_scope.
Notation "x ≤ y" := (BLe' x y) (at level 70, no associativity) : vimp_scope.
Notation "x == y" := (BEq' x y) (at level 70, no associativity) : vimp_scope.
Notation "x && y" := (BAnd' x y) (at level 40, left associativity) : vimp_scope.
Notation "'!' b" := (BNot' b) (at level 39, right associativity) : vimp_scope.

Coercion TNum : Z >-> term.
Coercion TId: logical_var >-> term.
Bind Scope term_scope with term.
Delimit Scope term_scope with term.

Notation "x + y" := (TPlus x y) (at level 50, left associativity) : term_scope.
Notation "x - y" := (TMinus x y) (at level 50, left associativity) : term_scope.
Notation "x * y" := (TMult x y) (at level 40, left associativity) : term_scope.
Notation "[[ a ]]" := (TDenote ((a)%vimp)) (at level 30, no associativity) : term_scope.
We choose not to create notations for ADeref' and AAddr'. Such that we do not need to parse two differnt * and &.
Fixpoint ainj (a: aexp): aexp' :=
  match a with
  | ANum nANum' (TNum n)
  | AId XAId' X
  | APlus a1 a2APlus' (ainj a1) (ainj a2)
  | AMinus a1 a2AMinus' (ainj a1) (ainj a2)
  | AMult a1 a2AMult' (ainj a1) (ainj a2)
  | ADeref a1ADeref' (ainj a1)
  | AAddr a1AAddr' (ainj a1)
  end.

Fixpoint binj (b : bexp): bexp' :=
  match b with
  | BTrueBTrue'
  | BFalseBFalse'
  | BEq a1 a2BEq' (ainj a1) (ainj a2)
  | BLe a1 a2BLe' (ainj a1) (ainj a2)
  | BNot b1BNot' (binj b1)
  | BAnd b1 b2BAnd' (binj b1) (binj b2)
  end.

Coercion ainj: aexp >-> aexp'.
Coercion binj: bexp >-> bexp'.

Inductive Assertion : Type :=
  | AssnLe (t1 t2 : term)
  | AssnLt (t1 t2 : term)
  | AssnEq (t1 t2 : term)
  | AssnMapsto (t1 t2 : term) (* <-- new *)
  | AssnSafeA (a: aexp') (* <-- new *)
  | AssnSafeB (b: bexp') (* <-- new *)
  | AssnDenote (b: bexp')
  | AssnOr (P1 P2 : Assertion)
  | AssnAnd (P1 P2 : Assertion)
  | AssnImpl (P1 P2 : Assertion)
  | AssnSep (P1 P2 : Assertion) (* <-- new *)
  | AssnEmp (* <-- new *)
  | AssnNot (P: Assertion)
  | AssnExists (x: logical_var) (P: Assertion)
  | AssnForall (x: logical_var) (P: Assertion).

Bind Scope assert_scope with Assertion.
Delimit Scope assert_scope with assert.

Notation "x ≤ y" := (AssnLe ((x)%term) ((y)%term)) (at level 70, no associativity) : assert_scope.
Notation "x '<' y" := (AssnLt ((x)%term) ((y)%term)) (at level 70, no associativity) : assert_scope.
Notation "x == y" := (AssnEq ((x)%term) ((y)%term)) (at level 70, no associativity) : assert_scope.
Notation "[[ b ]]" := (AssnDenote ((b)%vimp)) (at level 30, no associativity) : assert_scope.
Notation "P1 'SEP' P2" := (AssnSep P1 P2) (at level 72, left associativity) : assert_scope.
Notation "P1 'OR' P2" := (AssnOr P1 P2) (at level 76, left associativity) : assert_scope.
Notation "P1 'AND' P2" := (AssnAnd P1 P2) (at level 74, left associativity) : assert_scope.
Notation "P1 'IMPLY' P2" := (AssnImpl P1 P2) (at level 74, left associativity) : assert_scope.
Notation "'NOT' P" := (AssnNot P) (at level 73, right associativity) : assert_scope.
Notation "'EXISTS' x ',' P " := (AssnExists x ((P)%assert)) (at level 77, right associativity) : assert_scope.
Notation "'FORALL' x ',' P " := (AssnForall x ((P)%assert)) (at level 77, right associativity) : assert_scope.
Now, what we need is a new assignment rule:
    {{  SafeA(AAddr E1AND SafeA(E2AND [[AAddr E1]] == V1 AND [[E2]] == V2 AND
        Mapsto(V1VSEP P }}
    E1 ::= E2
    {{  Mapsto(V1V2SEP P }}
Adding all other Hoare logic proof rules together, it is enough to verify all programs. However, the following proof rule is more important in separation logic:
          {P }c {Q }}
    -----------------------------
    {P SEP F }c {Q SEP F }}
It is called frame rule.
End Separation_logic.

(* Mon Jun 10 15:13:09 UTC 2019 *)