Lecture notes 20190611

More Semantics 6 Separation 2

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: Programming Langauge


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).

Review: Assertion Language


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')
  | AAddr' (a1: aexp')
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.

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.

Hoare Logic for Assignment Commands

Here is our new proof rule:
    {{  SafeA(AAddr E1AND SafeA(E2AND [[AAddr E1]] == V1 AND [[E2]] == V2 AND
        Mapsto(V1VSEP P }}
    E1 ::= E2
    {{  Mapsto(V1V2SEP P }}
in which V1 and V2 are terms that are irrelevant to program states.
Let's see some examples. Remember SEP connects assertions tighter than AND.
Example 1. Here is a specification.
    {Mapsto([[AAddr X]],0) }}
    X ::= X + 1
    {Mapsto([[AAddr X]],1) }}
Suppose X is the 0th program variable. Here is a proof.
    {{    Mapsto([[AAddr X]],0)   }}
    {{    SafeA(AAddr XAND SafeA(X+1) AND
       [[AAddr X]] == 0 AND [[X+1]] == 1 AND
       Mapsto([[AAddr X]],0) SEP EMP }}
    X ::= X + 1
    {Mapsto([[AAddr X]],1) SEP EMP }}
    {Mapsto([[AAddr X]],1) }}
Example 2. Here is a specification.
    {Mapsto([[AAddr X]],0) SEP Mapsto([[AAddr Y]] , 0) }}
    X ::= X + 1
    {Mapsto([[AAddr X]],1) SEP Mapsto([[AAddr Y]] , 0) }}
Suppose X is program variable number 0 and Y is program variable number 1. Here is a proof.
    {Mapsto([[AAddr X]],0) SEP Mapsto([[AAddr Y]],0) }}
    {SafeA(AAddr XAND SafeA(X+1) AND
       [[AAddr X]] == 0 AND [[X+1]] == 1 AND
       Mapsto([[AAddr X]],0) SEP Mapsto([[AAddr Y]],0) }}
    X ::= X + 1
    {Mapsto([[AAddr X]],1) SEP Mapsto([[AAddr Y]],0) }}
Example 3. Here is a specification: forall x, y,
    {Mapsto([[AAddr X]],xSEP Mapsto([[AAddr Y]],y}}
    X ::= X + Y
    {Mapsto([[AAddr X]],x+ySEP Mapsto([[AAddr Y]],y}}
Suppose X is program variable number 0 and Y is program variable number 1. Here is a proof.
    {Mapsto([[AAddr X]],xSEP Mapsto([[AAddr Y]],y}}
    {SafeA(AAddr XAND SafeA(X+YAND
       [[AAddr X]] == 0 AND [[X+Y]] == x+y AND
       Mapsto([[AAddr X]],xSEP Mapsto([[AAddr Y]],y}}
    X ::= X + Y
    {Mapsto([[AAddr X]],x+ySEP Mapsto([[AAddr Y]],y}}.

The Frame Rule

The following proof rule is very important in separation logic:
           {P }c {Q }}
    ------------------------------------------
     {P SEP F }c {Q SEP F }}
It is called frame rule.
For example, suppose A, B and C are programs variables with indices 0, 1 and 2, respectively.
    {Mapsto(1, aSEP Mapsto(2, bSEP Mapsto(3, 0) }}
    ===> {Mapsto(1, aSEP Mapsto(3, 0) }}
         C ::= A;;
    <=== {Mapsto(1, aSEP Mapsto(3, a}}
    {Mapsto(1, aSEP Mapsto(2, bSEP Mapsto(3, a}}
    ===> {Mapsto(1, aSEP Mapsto(2, b}}
         A ::= B;;
    <=== {Mapsto(1, bSEP Mapsto(2, b}}
    {Mapsto(1, bSEP Mapsto(2, bSEP Mapsto(3, a}}
    ===> {Mapsto(2, bSEP Mapsto(3, a}}
         B ::= C;;
    <=== {Mapsto(2, aSEP Mapsto(3, a}}
    {Mapsto(1, aSEP Mapsto(2, bSEP Mapsto(3, a}}.
Maybe it is unnecessary in this example to use the frame rule but in general, it enables us to reason about a program locally but to apply the specification globally.
(* Mon Jun 10 15:58:06 UTC 2019 *)