Lecture notes 20190409
Denotational Semantics 3
Remark. Some material in this lecture is from << Software Foundation >>
volume 1 and volume 2.
Require Import Coq.Lists.List.
Require Import PL.Imp6.
Require Import PL.Imp6.
Module Expression_Denotation.
Fixpoint aeval (a : aexp) (st : state) : Z :=
match a with
| ANum n ⇒ n
| AId X ⇒ st X
| APlus a1 a2 ⇒ (aeval a1 st) + (aeval a2 st)
| AMinus a1 a2 ⇒ (aeval a1 st) - (aeval a2 st)
| AMult a1 a2 ⇒ (aeval a1 st) * (aeval a2 st)
end.
Fixpoint beval (b : bexp) (st : state) : Prop :=
match b with
| BTrue ⇒ True
| BFalse ⇒ False
| BEq a1 a2 ⇒ (aeval a1 st) = (aeval a2 st)
| BLe a1 a2 ⇒ (aeval a1 st) ≤ (aeval a2 st)
| BNot b1 ⇒ ¬(beval b1 st)
| BAnd b1 b2 ⇒ (beval b1 st) ∧ (beval b2 st)
end.
End Expression_Denotation.
Module Relation_Operators.
Definition id {A: Type}: A → A → Prop := fun a b ⇒ a = b.
Definition empty {A B: Type}: A → B → Prop := fun a b ⇒ False.
Definition concat {A B C: Type} (r1: A → B → Prop) (r2: B → C → Prop): A → C → Prop :=
fun a c ⇒ ∃b, r1 a b ∧ r2 b c.
Definition filter1 {A B: Type} (f: A → Prop): A → B → Prop :=
fun a b ⇒ f a.
Definition filter2 {A B: Type} (f: B → Prop): A → B → Prop :=
fun a b ⇒ f b.
Definition union {A B: Type} (r1 r2: A → B → Prop): A → B → Prop :=
fun a b ⇒ r1 a b ∨ r2 a b.
Definition intersection {A B: Type} (r1 r2: A → B → Prop): A → B → Prop :=
fun a b ⇒ r1 a b ∧ r2 a b.
Definition omega_union {A B: Type} (rs: nat → A → B → Prop): A → B → Prop :=
fun st1 st2 ⇒ ∃n, rs n st1 st2.
End Relation_Operators.
Module Command_Denotation_As_State_Relation.
Import Expression_Denotation.
Import Relation_Operators.
Definition if_sem
(b: bexp)
(then_branch else_branch: state → state → Prop)
: state → state → Prop
:=
union
(intersection then_branch (filter1 (beval b)))
(intersection else_branch (filter1 (beval (BNot b)))).
Fixpoint iter_loop_body
(b: bexp)
(loop_body: state → state → Prop)
(n: nat)
: state → state → Prop
:=
match n with
| O ⇒
intersection
id
(filter1 (beval (BNot b)))
| S n' ⇒
intersection
(concat
loop_body
(iter_loop_body b loop_body n'))
(filter1 (beval b))
end.
Definition loop_sem (b: bexp) (loop_body: state → state → Prop)
: state → state → Prop
:=
omega_union (iter_loop_body b loop_body).
Fixpoint ceval (c: com): state → state → Prop :=
match c with
| CSkip ⇒ id
| CAss X E ⇒
fun st1 st2 ⇒
st2 X = aeval E st1 ∧
∀Y, X ≠ Y → st1 Y = st2 Y
| CSeq c1 c2 ⇒ concat (ceval c1) (ceval c2)
| CIf b c1 c2 ⇒ if_sem b (ceval c1) (ceval c2)
| CWhile b c ⇒ loop_sem b (ceval c)
end.
Definition com_dequiv (d1 d2: state → state → Prop): Prop :=
∀st1 st2, d1 st1 st2 ↔ d2 st1 st2.
Theorem loop_recur: ∀b loop_body,
com_dequiv
(loop_sem b loop_body)
(union
(intersection
(concat loop_body
(loop_sem b loop_body))
(filter1 (beval b)))
(intersection
id
(filter1 (beval (BNot b))))).
Proof.
intros.
unfold com_dequiv.
intros.
split.
+ intros.
unfold loop_sem, omega_union in H.
unfold union.
destruct H as [n H].
destruct n as [| n'].
- right.
simpl in H.
exact H.
- left.
simpl in H.
unfold concat, intersection in H.
unfold concat, intersection.
destruct H as [[st' [? ?]] ?].
split.
* ∃st'.
split.
{ exact H. }
unfold loop_sem, omega_union.
∃n'.
exact H0.
* exact H1.
+ intros.
unfold loop_sem, omega_union.
unfold union in H.
destruct H.
- unfold intersection, concat in H.
destruct H as [[st' [? ?]] ?].
unfold loop_sem, omega_union in H0.
destruct H0 as [n ?].
∃(S n).
simpl.
unfold intersection, concat.
split.
* ∃st'.
split.
{ exact H. }
{ exact H0. }
* exact H1.
- ∃O.
simpl.
exact H.
Qed.
unfold com_dequiv.
intros.
split.
+ intros.
unfold loop_sem, omega_union in H.
unfold union.
destruct H as [n H].
destruct n as [| n'].
- right.
simpl in H.
exact H.
- left.
simpl in H.
unfold concat, intersection in H.
unfold concat, intersection.
destruct H as [[st' [? ?]] ?].
split.
* ∃st'.
split.
{ exact H. }
unfold loop_sem, omega_union.
∃n'.
exact H0.
* exact H1.
+ intros.
unfold loop_sem, omega_union.
unfold union in H.
destruct H.
- unfold intersection, concat in H.
destruct H as [[st' [? ?]] ?].
unfold loop_sem, omega_union in H0.
destruct H0 as [n ?].
∃(S n).
simpl.
unfold intersection, concat.
split.
* ∃st'.
split.
{ exact H. }
{ exact H0. }
* exact H1.
- ∃O.
simpl.
exact H.
Qed.
End Command_Denotation_As_State_Relation.
Module Bounded_Evaluation.
Import Expression_Denotation.
In this course, the expression evaluation of integer expressions is
unbounded, unlike the situation of normal programming languages like C and Java.
But still, we can define "whether evaluating an expression a" is within the
range of signed 32-bit integers. We define this property as an inductive
predicate in Coq.
Definition max32: Z := 2^31 -1.
Definition min32: Z := - 2^31.
Inductive signed32_eval: aexp → state → Z → Prop :=
| S32_ANum: ∀(n: Z) st,
min32 ≤ n ≤ max32 →
signed32_eval (ANum n) st n
| S32_AId: ∀(X: var) st,
min32 ≤ st X ≤ max32 →
signed32_eval (AId X) st (st X)
| S32_APlus: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 + v2 ≤ max32 →
signed32_eval (APlus a1 a2) st (v1 + v2)
| S32_AMinus: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 - v2 ≤ max32 →
signed32_eval (AMinus a1 a2) st (v1 - v2)
| S32_AMult: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 * v2 ≤ max32 →
signed32_eval (AMult a1 a2) st (v1 * v2).
Definition min32: Z := - 2^31.
Inductive signed32_eval: aexp → state → Z → Prop :=
| S32_ANum: ∀(n: Z) st,
min32 ≤ n ≤ max32 →
signed32_eval (ANum n) st n
| S32_AId: ∀(X: var) st,
min32 ≤ st X ≤ max32 →
signed32_eval (AId X) st (st X)
| S32_APlus: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 + v2 ≤ max32 →
signed32_eval (APlus a1 a2) st (v1 + v2)
| S32_AMinus: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 - v2 ≤ max32 →
signed32_eval (AMinus a1 a2) st (v1 - v2)
| S32_AMult: ∀a1 a2 st v1 v2,
signed32_eval a1 st v1 →
signed32_eval a2 st v2 →
min32 ≤ v1 * v2 ≤ max32 →
signed32_eval (AMult a1 a2) st (v1 * v2).
In short, signed32_eval a st v says that evaluating a on state st is
within the range of signed 32-bit integers (including all intermediate results)
the final result is v. Obviously, the evaluation result must coincide with
the expressions' denotations defined by aeval.
Theorem signed32_eval_correct: ∀a st v,
signed32_eval a st v →
aeval a st = v.
Proof.
(* WORKED IN CLASS *)
intros.
induction H.
+ simpl.
reflexivity.
+ simpl.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
Qed.
signed32_eval a st v →
aeval a st = v.
Proof.
(* WORKED IN CLASS *)
intros.
induction H.
+ simpl.
reflexivity.
+ simpl.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
+ simpl.
rewrite IHsigned32_eval1.
rewrite IHsigned32_eval2.
reflexivity.
Qed.
Similarly, we can defined 16-bit evaluation.
Definition max16: Z := 2^15 -1.
Definition min16: Z := - 2^15.
Inductive signed16_eval: aexp → state → Z → Prop :=
| S16_ANum: ∀(n: Z) st,
min16 ≤ n ≤ max16 →
signed16_eval (ANum n) st n
| S16_AId: ∀(X: var) st,
min16 ≤ st X ≤ max16 →
signed16_eval (AId X) st (st X)
| S16_APlus: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 + v2 ≤ max16 →
signed16_eval (APlus a1 a2) st (v1 + v2)
| S16_AMinus: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 - v2 ≤ max16 →
signed16_eval (AMinus a1 a2) st (v1 - v2)
| S16_AMult: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 * v2 ≤ max16 →
signed16_eval (AMult a1 a2) st (v1 * v2).
Definition min16: Z := - 2^15.
Inductive signed16_eval: aexp → state → Z → Prop :=
| S16_ANum: ∀(n: Z) st,
min16 ≤ n ≤ max16 →
signed16_eval (ANum n) st n
| S16_AId: ∀(X: var) st,
min16 ≤ st X ≤ max16 →
signed16_eval (AId X) st (st X)
| S16_APlus: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 + v2 ≤ max16 →
signed16_eval (APlus a1 a2) st (v1 + v2)
| S16_AMinus: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 - v2 ≤ max16 →
signed16_eval (AMinus a1 a2) st (v1 - v2)
| S16_AMult: ∀a1 a2 st v1 v2,
signed16_eval a1 st v1 →
signed16_eval a2 st v2 →
min16 ≤ v1 * v2 ≤ max16 →
signed16_eval (AMult a1 a2) st (v1 * v2).
Of course, 16-bit evaluation defines only a subset of 32-bit evaluation.
Second half of the proof is left as exercise.
Lemma range16_range32: ∀v,
min16 ≤ v ≤ max16 →
min32 ≤ v ≤ max32.
Proof.
intros.
unfold min16, max16 in H.
unfold min32, max32.
simpl in H.
simpl.
omega.
Qed.
min16 ≤ v ≤ max16 →
min32 ≤ v ≤ max32.
Proof.
intros.
unfold min16, max16 in H.
unfold min32, max32.
simpl in H.
simpl.
omega.
Qed.
EX2 (signed16_signed32)
Theorem signed16_signed32: ∀a st v,
signed16_eval a st v →
signed32_eval a st v.
Proof.
intros.
induction H.
+ apply S32_ANum.
apply range16_range32.
exact H.
(* FILL IN HERE *) Admitted.
☐
signed16_eval a st v →
signed32_eval a st v.
Proof.
intros.
induction H.
+ apply S32_ANum.
apply range16_range32.
exact H.
(* FILL IN HERE *) Admitted.
Inductive sub_aexp: aexp → aexp → Prop :=
| sub_aexp_refl: ∀e: aexp,
sub_aexp e e
| sub_aexp_APlus1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (APlus e1 e2)
| sub_aexp_APlus2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (APlus e1 e2)
| sub_aexp_AMinus1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (AMinus e1 e2)
| sub_aexp_AMinus2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (AMinus e1 e2)
| sub_aexp_AMult1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (AMult e1 e2)
| sub_aexp_AMult2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (AMult e1 e2).
| sub_aexp_refl: ∀e: aexp,
sub_aexp e e
| sub_aexp_APlus1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (APlus e1 e2)
| sub_aexp_APlus2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (APlus e1 e2)
| sub_aexp_AMinus1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (AMinus e1 e2)
| sub_aexp_AMinus2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (AMinus e1 e2)
| sub_aexp_AMult1: ∀e e1 e2: aexp,
sub_aexp e e1 →
sub_aexp e (AMult e1 e2)
| sub_aexp_AMult2: ∀e e1 e2: aexp,
sub_aexp e e2 →
sub_aexp e (AMult e1 e2).
Theorem signed32_eval_sub_aexp: ∀e1 e2 st,
sub_aexp e1 e2 →
(∃v2, signed32_eval e2 st v2) →
(∃v1, signed32_eval e1 st v1).
Proof.
intros.
(* FILL IN HERE *) Admitted.
☐
sub_aexp e1 e2 →
(∃v2, signed32_eval e2 st v2) →
(∃v1, signed32_eval e1 st v1).
Proof.
intros.
(* FILL IN HERE *) Admitted.
End Bounded_Evaluation.
Module Loop_Free.
Import Expression_Denotation.
Import Relation_Operators.
Import Command_Denotation_As_State_Relation.
Now, we prove that a loop free program always terminate.
Inductive loop_free: com → Prop :=
| loop_free_skip:
loop_free Skip
| loop_free_asgn: ∀X E,
loop_free (CAss X E)
| loop_free_seq: ∀c1 c2,
loop_free c1 →
loop_free c2 →
loop_free (c1 ;; c2)
| loop_free_if: ∀b c1 c2,
loop_free c1 →
loop_free c2 →
loop_free (If b Then c1 Else c2 EndIf).
Theorem loop_free_terminate: ∀c,
loop_free c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
intros.
| loop_free_skip:
loop_free Skip
| loop_free_asgn: ∀X E,
loop_free (CAss X E)
| loop_free_seq: ∀c1 c2,
loop_free c1 →
loop_free c2 →
loop_free (c1 ;; c2)
| loop_free_if: ∀b c1 c2,
loop_free c1 →
loop_free c2 →
loop_free (If b Then c1 Else c2 EndIf).
Theorem loop_free_terminate: ∀c,
loop_free c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
intros.
Try to understand why we need to strengthen the induction hypothesis
here.
revert st1.
induction H; intros.
+ ∃st1.
unfold ceval.
unfold id.
reflexivity.
+ unfold ceval.
induction H; intros.
+ ∃st1.
unfold ceval.
unfold id.
reflexivity.
+ unfold ceval.
Oops! We need to construct such a program state st2.
Abort.
Definition state_update (st: state) (X: var) (v: Z): state :=
fun Y ⇒ if (Nat.eq_dec X Y) then v else st Y.
Definition state_update (st: state) (X: var) (v: Z): state :=
fun Y ⇒ if (Nat.eq_dec X Y) then v else st Y.
Here, we define a program state, i.e. a new function from program variables
to integers. This program state is almost the same as st but only differs
with st on X's value. X's new value will be v.
The Coq expression if (Nat.eq_dec X Y) then _ else _ says, if X and Y are
the same variable, do the calculation described by then; otherwise do the
calculation defined by else. In proofs, we can write destruct (Nat.eq_dec X Y)
to do case analysis on whether X and Y are the same variable.
It is worth one more sentence emphasizing that Nat.eq_dec X Y is not to tell
whether their values are the same; it tells whether they are the same variable.
You might be curious why Nat appears here. Here is some explanation.
You do not need understand all of this. You can freely skip it if you want.
If you take a look at how "variables" are formalized in Imp, you would find
that they are just names! And different variables are just represented by
different natural numbers, i.e. 1st variable, 2nd variable, etc. That is why to
determine whether two variable names are the same is to determine whether two
natural numbers are the same.
End of the contents which you can skip.
Lemma state_update_spec: ∀st X v,
(state_update st X v) X = v ∧
(∀Y, X ≠ Y → st Y = (state_update st X v) Y).
Proof.
intros.
unfold state_update.
split.
+ destruct (Nat.eq_dec X X).
- reflexivity.
- assert (X = X). { reflexivity. }
tauto.
+ intros.
destruct (Nat.eq_dec X Y).
- tauto.
- reflexivity.
Qed.
(state_update st X v) X = v ∧
(∀Y, X ≠ Y → st Y = (state_update st X v) Y).
Proof.
intros.
unfold state_update.
split.
+ destruct (Nat.eq_dec X X).
- reflexivity.
- assert (X = X). { reflexivity. }
tauto.
+ intros.
destruct (Nat.eq_dec X Y).
- tauto.
- reflexivity.
Qed.
Theorem loop_free_terminate: ∀c,
loop_free c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
intros.
revert st1.
induction H; intros.
+ ∃st1.
unfold ceval.
unfold id.
reflexivity.
+ unfold ceval.
∃(state_update st1 X (aeval E st1)).
apply state_update_spec.
loop_free c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
intros.
revert st1.
induction H; intros.
+ ∃st1.
unfold ceval.
unfold id.
reflexivity.
+ unfold ceval.
∃(state_update st1 X (aeval E st1)).
apply state_update_spec.
The other two cases are left as exercise.
(* FILL IN HERE *) Admitted.
☐
Fixpoint loop_free_fun (c: com): Prop :=
match c with
| CSkip ⇒ True
| CAss _ _ ⇒ True
| CSeq c1 c2 ⇒ loop_free_fun c1 ∧ loop_free_fun c2
| CIf b c1 c2 ⇒ loop_free_fun c1 ∧ loop_free_fun c2
| CWhile _ _ ⇒ False
end.
match c with
| CSkip ⇒ True
| CAss _ _ ⇒ True
| CSeq c1 c2 ⇒ loop_free_fun c1 ∧ loop_free_fun c2
| CIf b c1 c2 ⇒ loop_free_fun c1 ∧ loop_free_fun c2
| CWhile _ _ ⇒ False
end.
It is no problem. And you can try to prove a similar theorem about
termination.
Exercise: 2 stars, standard (loop_free_fun_terminate)
Theorem loop_free_fun_terminate: ∀c,
loop_free_fun c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
(* FILL IN HERE *) Admitted.
☐
loop_free_fun c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
(* FILL IN HERE *) Admitted.
Inductive loop_free': com → Prop :=
| loop_free'_skip:
loop_free' Skip
| loop_free'_asgn: ∀X E,
loop_free' (CAss X E)
| loop_free'_seq: ∀c1 c2,
loop_free' c1 →
loop_free' c2 →
loop_free' (c1 ;; c2)
| loop_free'_if: ∀b c1 c2,
loop_free' c1 →
loop_free' c2 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_if_then: ∀b c1 c2,
(∀st, beval b st) →
loop_free' c1 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_if_else: ∀b c1 c2,
(∀st, ¬beval b st) →
loop_free' c2 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_while_false: ∀b c,
(∀st, ¬beval b st) →
loop_free' (While b Do c EndWhile).
| loop_free'_skip:
loop_free' Skip
| loop_free'_asgn: ∀X E,
loop_free' (CAss X E)
| loop_free'_seq: ∀c1 c2,
loop_free' c1 →
loop_free' c2 →
loop_free' (c1 ;; c2)
| loop_free'_if: ∀b c1 c2,
loop_free' c1 →
loop_free' c2 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_if_then: ∀b c1 c2,
(∀st, beval b st) →
loop_free' c1 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_if_else: ∀b c1 c2,
(∀st, ¬beval b st) →
loop_free' c2 →
loop_free' (If b Then c1 Else c2 EndIf)
| loop_free'_while_false: ∀b c,
(∀st, ¬beval b st) →
loop_free' (While b Do c EndWhile).
This definition says: if an if-condition is always true, then the loops in
its else-branch should not be considered as real loops. Similarly, if an
if-condition is always false, then the loops in its then-branch should not be
considered as real loops. Also, if a while-loop's loop condition is always
false, the loop body will never be executed — that is not a real loop either.
Exercise: 2 stars, standard (loop_free'_terminate)
Theorem loop_free'_terminate: ∀c,
loop_free' c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
(* FILL IN HERE *) Admitted.
☐
loop_free' c →
(∀st1, ∃st2, ceval c st1 st2).
Proof.
(* FILL IN HERE *) Admitted.
End Loop_Free.
Other Denotational Semantics
Module Command_Denotation_Inductively_Defined.
Import Expression_Denotation.
Import Relation_Operators.
Import Expression_Denotation.
Import Relation_Operators.
The following semantic definition states the same definition by a Coq
inductive predicate.
Inductive ceval : com → state → state → Prop :=
| E_Skip : ∀st,
ceval CSkip st st
| E_Ass : ∀st1 st2 X E,
st2 X = aeval E st1 →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
ceval (CAss X E) st1 st2
| E_Seq : ∀c1 c2 st st' st'',
ceval c1 st st' →
ceval c2 st' st'' →
ceval (c1 ;; c2) st st''
| E_IfTrue : ∀st st' b c1 c2,
beval b st →
ceval c1 st st' →
ceval (If b Then c1 Else c2 EndIf) st st'
| E_IfFalse : ∀st st' b c1 c2,
¬beval b st →
ceval c2 st st' →
ceval (If b Then c1 Else c2 EndIf) st st'
| E_WhileFalse : ∀b st c,
¬beval b st →
ceval (While b Do c EndWhile) st st
| E_WhileTrue : ∀st st' st'' b c,
beval b st →
ceval c st st' →
ceval (While b Do c EndWhile) st' st'' →
ceval (While b Do c EndWhile) st st''.
Definition com_dequiv (d1 d2: state → state → Prop): Prop :=
∀st1 st2, d1 st1 st2 ↔ d2 st1 st2.
| E_Skip : ∀st,
ceval CSkip st st
| E_Ass : ∀st1 st2 X E,
st2 X = aeval E st1 →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
ceval (CAss X E) st1 st2
| E_Seq : ∀c1 c2 st st' st'',
ceval c1 st st' →
ceval c2 st' st'' →
ceval (c1 ;; c2) st st''
| E_IfTrue : ∀st st' b c1 c2,
beval b st →
ceval c1 st st' →
ceval (If b Then c1 Else c2 EndIf) st st'
| E_IfFalse : ∀st st' b c1 c2,
¬beval b st →
ceval c2 st st' →
ceval (If b Then c1 Else c2 EndIf) st st'
| E_WhileFalse : ∀b st c,
¬beval b st →
ceval (While b Do c EndWhile) st st
| E_WhileTrue : ∀st st' st'' b c,
beval b st →
ceval c st st' →
ceval (While b Do c EndWhile) st' st'' →
ceval (While b Do c EndWhile) st st''.
Definition com_dequiv (d1 d2: state → state → Prop): Prop :=
∀st1 st2, d1 st1 st2 ↔ d2 st1 st2.
And we can prove that it has all same properties as our original
definition. Here is only an example.
Exercise: 2 stars, standard (ceval_Cseq_spec)
Lemma ceval_CSeq_spec: ∀c1 c2,
com_dequiv (ceval (c1;; c2)) (concat (ceval c1) (ceval c2)).
Proof.
(* FILL IN HERE *) Admitted.
☐
com_dequiv (ceval (c1;; c2)) (concat (ceval c1) (ceval c2)).
Proof.
(* FILL IN HERE *) Admitted.
End Command_Denotation_Inductively_Defined.
Module Command_Denotation_With_Steps.
Import Expression_Denotation.
Module Command_Denotation_With_Steps.
Import Expression_Denotation.
This time, a program's denotation is defined as a trinary relation.
Specifically, st1, t, st2 belongs to the denotation of program c if and
only if executing c from st1 may take time t and stop at state st2.
Definition skip_sem: state → Z → state → Prop :=
fun st1 t st2 ⇒
st1 = st2 ∧ t = 0.
Definition asgn_sem (X: var) (E: aexp): state → Z → state → Prop :=
fun st1 t st2 ⇒
st2 X = aeval E st1 ∧
∀Y, X ≠ Y → st1 Y = st2 Y ∧
t = 1.
fun st1 t st2 ⇒
st1 = st2 ∧ t = 0.
Definition asgn_sem (X: var) (E: aexp): state → Z → state → Prop :=
fun st1 t st2 ⇒
st2 X = aeval E st1 ∧
∀Y, X ≠ Y → st1 Y = st2 Y ∧
t = 1.
Here we assume every assignment command takes one unit of time. We can
write a more realistic definition here so that different assignment commands
may take different amount of time.
Definition seq_sem (d1 d2: state → Z → state → Prop)
: state → Z → state → Prop
:=
fun st1 t st3 ⇒
∃t1 t2 st2,
d1 st1 t1 st2 ∧ d2 st2 t2 st3 ∧ t = t1 + t2.
Definition if_sem (b: bexp) (d1 d2: state → Z → state → Prop)
: state → Z → state → Prop
:=
fun st1 t st2 ⇒
(d1 st1 (t - 1) st2 ∧ beval b st1) ∨
(d2 st1 (t - 1) st2 ∧ ¬beval b st1).
: state → Z → state → Prop
:=
fun st1 t st3 ⇒
∃t1 t2 st2,
d1 st1 t1 st2 ∧ d2 st2 t2 st3 ∧ t = t1 + t2.
Definition if_sem (b: bexp) (d1 d2: state → Z → state → Prop)
: state → Z → state → Prop
:=
fun st1 t st2 ⇒
(d1 st1 (t - 1) st2 ∧ beval b st1) ∨
(d2 st1 (t - 1) st2 ∧ ¬beval b st1).
Here we assume that testing an if-condition will take one unit of time.
Fixpoint iter_loop_body
(b: bexp)
(loop_body: state → Z → state → Prop)
(n: nat)
: state → Z → state → Prop
:=
match n with
| O ⇒
fun st1 t st2 ⇒
(st1 = st2 ∧ t = 1) ∧ ¬beval b st1
| S n' ⇒
fun st1 t st3 ⇒
(∃t1 t2 st2,
(loop_body) st1 t1 st2 ∧
(iter_loop_body b loop_body n') st2 t2 st3 ∧
t = t1 + t2) ∧
beval b st1
end.
(b: bexp)
(loop_body: state → Z → state → Prop)
(n: nat)
: state → Z → state → Prop
:=
match n with
| O ⇒
fun st1 t st2 ⇒
(st1 = st2 ∧ t = 1) ∧ ¬beval b st1
| S n' ⇒
fun st1 t st3 ⇒
(∃t1 t2 st2,
(loop_body) st1 t1 st2 ∧
(iter_loop_body b loop_body n') st2 t2 st3 ∧
t = t1 + t2) ∧
beval b st1
end.
Here we assume that testing a loop condition will take one unit of time.
Definition loop_sem (b: bexp) (loop_body: state → Z → state → Prop)
: state → Z → state → Prop
:=
fun st1 t st2 ⇒
∃n, (iter_loop_body b loop_body n) st1 t st2.
Fixpoint ceval (c: com): state → Z → state → Prop :=
match c with
| CSkip ⇒ skip_sem
| CAss X E ⇒ asgn_sem X E
| CSeq c1 c2 ⇒ seq_sem (ceval c1) (ceval c2)
| CIf b c1 c2 ⇒ if_sem b (ceval c1) (ceval c2)
| CWhile b c ⇒ loop_sem b (ceval c)
end.
End Command_Denotation_With_Steps.
Module Command_Denotation_State_Trace.
Import Expression_Denotation.
: state → Z → state → Prop
:=
fun st1 t st2 ⇒
∃n, (iter_loop_body b loop_body n) st1 t st2.
Fixpoint ceval (c: com): state → Z → state → Prop :=
match c with
| CSkip ⇒ skip_sem
| CAss X E ⇒ asgn_sem X E
| CSeq c1 c2 ⇒ seq_sem (ceval c1) (ceval c2)
| CIf b c1 c2 ⇒ if_sem b (ceval c1) (ceval c2)
| CWhile b c ⇒ loop_sem b (ceval c)
end.
End Command_Denotation_With_Steps.
Module Command_Denotation_State_Trace.
Import Expression_Denotation.
This time, a program's denotation is defined as a different trinary
relation — the relation of beginning states, intermediate traces and ending
states. For conciseness, we assume that an intermediate state trace does not
include the beginning state but includes the ending state.
Definition skip_sem: state → list state → state → Prop :=
fun st1 tr st2 ⇒
st1 = st2 ∧ tr = nil.
Definition asgn_sem (X: var) (E: aexp): state → list state → state → Prop :=
fun st1 tr st2 ⇒
st2 X = aeval E st1 ∧
∀Y, X ≠ Y → st1 Y = st2 Y ∧
tr = st2 :: nil.
Definition seq_sem (d1 d2: state → list state → state → Prop)
: state → list state → state → Prop
:=
fun st1 tr st3 ⇒
∃tr1 tr2 st2,
d1 st1 tr1 st2 ∧ d2 st2 tr2 st3 ∧ tr = tr1 ++ tr2.
Definition if_sem (b: bexp) (d1 d2: state → list state → state → Prop)
: state → list state → state → Prop
:=
fun st1 tr st2 ⇒
(∃tr', tr = st1 :: tr' ∧ d1 st1 tr' st2 ∧ beval b st1) ∨
(∃tr', tr = st1 :: tr' ∧ d2 st1 tr' st2 ∧ ¬beval b st1).
Fixpoint iter_loop_body
(b: bexp)
(loop_body: state → list state → state → Prop)
(n: nat)
: state → list state → state → Prop
:=
match n with
| O ⇒
fun st1 tr st2 ⇒
(st1 = st2 ∧ tr = nil) ∧ ¬beval b st1
| S n' ⇒
fun st1 tr st3 ⇒
(∃tr1 tr2 st2,
(loop_body) st1 tr1 st2 ∧
(iter_loop_body b loop_body n') st2 tr2 st3 ∧
tr = st1 :: tr1 ++ tr2) ∧
beval b st1
end.
fun st1 tr st2 ⇒
st1 = st2 ∧ tr = nil.
Definition asgn_sem (X: var) (E: aexp): state → list state → state → Prop :=
fun st1 tr st2 ⇒
st2 X = aeval E st1 ∧
∀Y, X ≠ Y → st1 Y = st2 Y ∧
tr = st2 :: nil.
Definition seq_sem (d1 d2: state → list state → state → Prop)
: state → list state → state → Prop
:=
fun st1 tr st3 ⇒
∃tr1 tr2 st2,
d1 st1 tr1 st2 ∧ d2 st2 tr2 st3 ∧ tr = tr1 ++ tr2.
Definition if_sem (b: bexp) (d1 d2: state → list state → state → Prop)
: state → list state → state → Prop
:=
fun st1 tr st2 ⇒
(∃tr', tr = st1 :: tr' ∧ d1 st1 tr' st2 ∧ beval b st1) ∨
(∃tr', tr = st1 :: tr' ∧ d2 st1 tr' st2 ∧ ¬beval b st1).
Fixpoint iter_loop_body
(b: bexp)
(loop_body: state → list state → state → Prop)
(n: nat)
: state → list state → state → Prop
:=
match n with
| O ⇒
fun st1 tr st2 ⇒
(st1 = st2 ∧ tr = nil) ∧ ¬beval b st1
| S n' ⇒
fun st1 tr st3 ⇒
(∃tr1 tr2 st2,
(loop_body) st1 tr1 st2 ∧
(iter_loop_body b loop_body n') st2 tr2 st3 ∧
tr = st1 :: tr1 ++ tr2) ∧
beval b st1
end.
Here we assume that testing an if-condition or a loop condition will have a
footprint in program execution's state traces.
Definition loop_sem (b: bexp) (loop_body: state → list state → state → Prop)
: state → list state → state → Prop
:=
fun st1 tr st2 ⇒
∃n, (iter_loop_body b loop_body n) st1 tr st2.
Fixpoint ceval (c: com): state → list state → state → Prop :=
match c with
| CSkip ⇒ skip_sem
| CAss X E ⇒ asgn_sem X E
| CSeq c1 c2 ⇒ seq_sem (ceval c1) (ceval c2)
| CIf b c1 c2 ⇒ if_sem b (ceval c1) (ceval c2)
| CWhile b c ⇒ loop_sem b (ceval c)
end.
Definition com_dequiv (d1 d2: state → list state → state → Prop): Prop :=
∀st1 tr st2, d1 st1 tr st2 ↔ d2 st1 tr st2.
: state → list state → state → Prop
:=
fun st1 tr st2 ⇒
∃n, (iter_loop_body b loop_body n) st1 tr st2.
Fixpoint ceval (c: com): state → list state → state → Prop :=
match c with
| CSkip ⇒ skip_sem
| CAss X E ⇒ asgn_sem X E
| CSeq c1 c2 ⇒ seq_sem (ceval c1) (ceval c2)
| CIf b c1 c2 ⇒ if_sem b (ceval c1) (ceval c2)
| CWhile b c ⇒ loop_sem b (ceval c)
end.
Definition com_dequiv (d1 d2: state → list state → state → Prop): Prop :=
∀st1 tr st2, d1 st1 tr st2 ↔ d2 st1 tr st2.
Lemma seq_sem_assoc: ∀d1 d2 d3,
com_dequiv (seq_sem (seq_sem d1 d2) d3) (seq_sem d1 (seq_sem d2 d3)).
Proof.
(* FILL IN HERE *) Admitted.
☐
com_dequiv (seq_sem (seq_sem d1 d2) d3) (seq_sem d1 (seq_sem d2 d3)).
Proof.
(* FILL IN HERE *) Admitted.
End Command_Denotation_State_Trace.
(* Tue Apr 9 02:48:59 UTC 2019 *)
(* Tue Apr 9 02:48:59 UTC 2019 *)