Lecture notes 20190416
Small Step Semantics 2
Require Import PL.Imp6.
Require Import Coq.Relations.Relation_Operators.
Require Import Coq.Relations.Relation_Definitions.
Arguments clos_refl_trans {A} _ _ _.
Arguments clos_refl_trans_1n {A} _ _ _.
Arguments clos_refl_trans_n1 {A} _ _ _.
Require Import Coq.Relations.Relation_Operators.
Require Import Coq.Relations.Relation_Definitions.
Arguments clos_refl_trans {A} _ _ _.
Arguments clos_refl_trans_1n {A} _ _ _.
Arguments clos_refl_trans_n1 {A} _ _ _.
Inductive aexp_halt: aexp → Prop :=
| AH_num : ∀n, aexp_halt (ANum n).
Inductive astep : state → aexp → aexp → Prop :=
| AS_Id : ∀st X,
astep st
(AId X) (ANum (st X))
| AS_Plus1 : ∀st a1 a1' a2,
astep st
a1 a1' →
astep st
(APlus a1 a2) (APlus a1' a2)
| AS_Plus2 : ∀st a1 a2 a2',
aexp_halt a1 →
astep st
a2 a2' →
astep st
(APlus a1 a2) (APlus a1 a2')
| AS_Plus : ∀st n1 n2,
astep st
(APlus (ANum n1) (ANum n2)) (ANum (n1 + n2))
| AS_Minus1 : ∀st a1 a1' a2,
astep st
a1 a1' →
astep st
(AMinus a1 a2) (AMinus a1' a2)
| AS_Minus2 : ∀st a1 a2 a2',
aexp_halt a1 →
astep st
a2 a2' →
astep st
(AMinus a1 a2) (AMinus a1 a2')
| AS_Minus : ∀st n1 n2,
astep st
(AMinus (ANum n1) (ANum n2)) (ANum (n1 - n2))
| AS_Mult1 : ∀st a1 a1' a2,
astep st
a1 a1' →
astep st
(AMult a1 a2) (AMult a1' a2)
| AS_Mult2 : ∀st a1 a2 a2',
aexp_halt a1 →
astep st
a2 a2' →
astep st
(AMult a1 a2) (AMult a1 a2')
| AS_Mult : ∀st n1 n2,
astep st
(AMult (ANum n1) (ANum n2)) (ANum (n1 * n2)).
Inductive bexp_halt: bexp → Prop :=
| BH_True : bexp_halt BTrue
| BH_False : bexp_halt BFalse.
Inductive bstep : state → bexp → bexp → Prop :=
| BS_Eq1 : ∀st a1 a1' a2,
astep st
a1 a1' →
bstep st
(BEq a1 a2) (BEq a1' a2)
| BS_Eq2 : ∀st a1 a2 a2',
aexp_halt a1 →
astep 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,
n1 ≠ n2 →
bstep st
(BEq (ANum n1) (ANum n2)) BFalse
| BS_Le1 : ∀st a1 a1' a2,
astep st
a1 a1' →
bstep st
(BLe a1 a2) (BLe a1' a2)
| BS_Le2 : ∀st a1 a2 a2',
aexp_halt a1 →
astep st
a2 a2' →
bstep st
(BLe a1 a2) (BLe a1 a2')
| BS_Le_True : ∀st n1 n2,
n1 ≤ n2 →
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.
Multi-step Relation
Definition multi_astep (st: state): aexp → aexp → Prop := clos_refl_trans (astep st).
Definition multi_bstep (st: state): bexp → bexp → Prop := clos_refl_trans (bstep st).
Definition multi_bstep (st: state): bexp → bexp → Prop := clos_refl_trans (bstep st).
Intuitively, if multi_astep st a1 a2 is true, then a2 is an intermidiate
result of evaluating a1 on st. And multi_bstep st b1 b2 says that b2 is
an intermidiate result of evaluating b1 on st. Here is several examples.
Module Example1.
Import Abstract_Pretty_Printing.
Example multi_step_ex1: ∀(Y: var) (st: state),
st Y = 2 →
multi_astep st (1 + (3 +Y)) (1 + 5).
Example multi_step_ex2: ∀(X: var) (st: state),
st X = 1 →
multi_bstep st ((X ≤ 0) && (0 ≤ X + 10)) BFalse.
Example multi_step_ex3: ∀(X: var) (st: state),
st X = 1 →
multi_bstep st ((X ≤ 0) && (0 ≤ X + 10)) ((X ≤ 0) && (0 ≤ X + 10)).
End Example1.
Import Abstract_Pretty_Printing.
Example multi_step_ex1: ∀(Y: var) (st: state),
st Y = 2 →
multi_astep st (1 + (3 +Y)) (1 + 5).
Proof.
intros.
eapply rt_trans.
+ apply rt_step.
apply AS_Plus2.
{ apply AH_num. }
apply AS_Plus2.
{ apply AH_num. }
apply AS_Id.
+ rewrite H.
apply rt_step.
apply AS_Plus2.
{ apply AH_num. }
apply AS_Plus.
Qed.
intros.
eapply rt_trans.
+ apply rt_step.
apply AS_Plus2.
{ apply AH_num. }
apply AS_Plus2.
{ apply AH_num. }
apply AS_Id.
+ rewrite H.
apply rt_step.
apply AS_Plus2.
{ apply AH_num. }
apply AS_Plus.
Qed.
Example multi_step_ex2: ∀(X: var) (st: state),
st X = 1 →
multi_bstep st ((X ≤ 0) && (0 ≤ X + 10)) BFalse.
Proof.
intros.
eapply rt_trans.
{ apply rt_step. apply BS_AndStep. apply BS_Le1. apply AS_Id. }
rewrite H.
eapply rt_trans.
{ apply rt_step. apply BS_AndStep. apply BS_Le_False. omega. }
{ apply rt_step. apply BS_AndFalse. }
Qed.
intros.
eapply rt_trans.
{ apply rt_step. apply BS_AndStep. apply BS_Le1. apply AS_Id. }
rewrite H.
eapply rt_trans.
{ apply rt_step. apply BS_AndStep. apply BS_Le_False. omega. }
{ apply rt_step. apply BS_AndFalse. }
Qed.
Example multi_step_ex3: ∀(X: var) (st: state),
st X = 1 →
multi_bstep st ((X ≤ 0) && (0 ≤ X + 10)) ((X ≤ 0) && (0 ≤ X + 10)).
Proof.
intros.
apply rt_refl.
Qed.
intros.
apply rt_refl.
Qed.
End Example1.
The multi-step relations satisfy the congruence property. For example,
Theorem multi_congr_APlus1: ∀st a1 a1' a2,
multi_astep st a1 a1' →
multi_astep st (a1 + a2) (a1' + a2).
Proof.
multi_astep st a1 a1' →
multi_astep st (a1 + a2) (a1' + a2).
Proof.
Why? Because for every single step from a1 to a1', we can construct
a corresponding step from a1 + a2 to a1' + a2.
intros.
unfold multi_astep in H.
unfold multi_astep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply AS_Plus1.
exact H.
- apply IHclos_refl_trans_n1.
Qed.
unfold multi_astep in H.
unfold multi_astep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply AS_Plus1.
exact H.
- apply IHclos_refl_trans_n1.
Qed.
Remark: we could complete this proof using clos_refl_trans instead of
clos_refl_trans_n1. We pick this choice just for convenience.
Theorem multi_congr_APlus2: ∀st a1 a2 a2',
aexp_halt a1 →
multi_astep st a2 a2' →
multi_astep st (a1 + a2) (a1 + a2').
Proof.
aexp_halt a1 →
multi_astep st a2 a2' →
multi_astep st (a1 + a2) (a1 + a2').
Proof.
It is critical that we require a1 to be a constant.
intros.
unfold multi_astep in H.
unfold multi_astep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H0.
induction H0.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply AS_Plus2.
unfold multi_astep in H.
unfold multi_astep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H0.
induction H0.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply AS_Plus2.
Here we go. Without the assumption H: aexp_halt a1, we cannot
complete our proof here.
* exact H.
* exact H0.
- apply IHclos_refl_trans_n1.
Qed.
* exact H0.
- apply IHclos_refl_trans_n1.
Qed.
We can prove similar properties for AMinus, AMult, BEq, BLe, BNot
and BAnd.
The semantics of commands is more interesting. For expression evaluation,
the program states are stable. In other words, we only talked about how an
expression will be reduced to another one on a fixed program state. But for
program execution, the program states are modified. Thus, a ternary relation
among the program state, the command to execute and the residue command after
one step is not expressive enough to describe programs' behavior. A quaternary
relation is needed.
Specifically, we would like to define a predicate cstep such that
Traditionally, computer scientist will describe their theory in a slightly
different form. They usually treat cstep as a binary relation between
state-command pairs and use the following notation:
Small Step Semantics for Simple Imperative Programes
cstep st1 c1 st2 c2
says if the program to execute is c1, the taking one step forward on state
st1 may end in state st2 while the residue command is c2.
(st1, c1) --> (st2, c2).
We will follow this style in our course, i.e. we will write
cstep (st1, c1) (st2, c2).
Coq Data Type: Pairs
Module Playground.
In Coq, product types are defined as the follow polymorphic inductive type.
This declaration can be read: "There is just one way to construct an A-B pair:
by applying the constructor pair to two arguments of type A and B."
Inductive prod (A B : Type) : Type :=
| pair (a : A) (b : B).
Arguments pair {A} {B} _ _.
Notation "( a , b )" := (pair a b).
Notation "A * B" := (prod A B) : type_scope.
Check (pair 3 5).
| pair (a : A) (b : B).
Arguments pair {A} {B} _ _.
Notation "( a , b )" := (pair a b).
Notation "A * B" := (prod A B) : type_scope.
Check (pair 3 5).
Here are simple functions for extracting the first and second components of a pair.
Definition fst {A B: Type} (p : A * B) : A :=
match p with
| pair x y ⇒ x
end.
Definition snd {A B: Type} (p : A * B) : B :=
match p with
| pair x y ⇒ y
end.
Example fst_example:
fst (3, 5) = 3.
Proof. reflexivity. Qed.
match p with
| pair x y ⇒ x
end.
Definition snd {A B: Type} (p : A * B) : B :=
match p with
| pair x y ⇒ y
end.
Example fst_example:
fst (3, 5) = 3.
Proof. reflexivity. Qed.
Note that the pair notation can also be used in pattern matching.
Definition swap_pair {A B: Type} (p : A * B): B * A :=
match p with
| (x,y) ⇒ (y,x)
end.
match p with
| (x,y) ⇒ (y,x)
end.
Let's try to prove a few simple facts about pairs. If we state things in a
slightly peculiar way, we can complete proofs with just reflexivity (and its
built-in simplification):
Theorem surjective_pairing' : ∀(n m : Z),
(n,m) = (fst (n,m), snd (n,m)).
Proof. intros. reflexivity. Qed.
(n,m) = (fst (n,m), snd (n,m)).
Proof. intros. reflexivity. Qed.
Here, we can see the effect of simpl.
Theorem surjective_pairing'_alter : ∀(n m : Z),
(n,m) = (fst (n,m), snd (n,m)).
Proof. intros. simpl. reflexivity. Qed.
(n,m) = (fst (n,m), snd (n,m)).
Proof. intros. simpl. reflexivity. Qed.
But reflexivity is not enough if we state the lemma in a more natural
way:
Theorem surjective_pairing_stuck : ∀(p : Z * Z),
p = (fst p, snd p).
Proof.
intros.
simpl. (* Doesn't reduce anything! *)
Abort.
p = (fst p, snd p).
Proof.
intros.
simpl. (* Doesn't reduce anything! *)
Abort.
We have to expose the structure of p so that simpl can perform
the pattern match in fst and snd. We can do this with destruct.
Theorem surjective_pairing : ∀(p : Z * Z),
p = (fst p, snd p).
Proof.
intros p.
destruct p as [n m].
simpl.
reflexivity.
Qed.
p = (fst p, snd p).
Proof.
intros p.
destruct p as [n m].
simpl.
reflexivity.
Qed.
Theorem snd_fst_is_swap : ∀{A B: Type} (p : A * B),
(snd p, fst p) = swap_pair p.
Proof.
(* FILL IN HERE *) Admitted.
☐
(snd p, fst p) = swap_pair p.
Proof.
(* FILL IN HERE *) Admitted.
Theorem fst_swap_is_snd : ∀{A B: Type} (p : A * B),
fst (swap_pair p) = snd p.
Proof.
(* FILL IN HERE *) Admitted.
☐
fst (swap_pair p) = snd p.
Proof.
(* FILL IN HERE *) Admitted.
End Playground.
These definitions about pairs are all built in Coq's standard library.
Print prod.
(* Inductive prod (A B : Type) : Type := pair : A -> B -> A * B *)
Check fst.
(* fst : ?A * ?B -> ?A *)
Check fst.
(* snd : ?A * ?B -> ?B *)
(* Inductive prod (A B : Type) : Type := pair : A -> B -> A * B *)
Check fst.
(* fst : ?A * ?B -> ?A *)
Check fst.
(* snd : ?A * ?B -> ?B *)
Definition of Program Steps
Import Abstract_Pretty_Printing.
Local Open Scope imp.
Inductive cstep : (com * state) → (com * state) → Prop :=
| CS_AssStep : ∀st X a a',
astep st a a' →
cstep (CAss X a, st) (CAss X a', st)
| CS_Ass : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep : ∀st c1 c1' st' c2,
cstep (c1, st) (c1', st') →
cstep (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq : ∀st c2,
cstep (Skip ;; c2, st) (c2, st)
| CS_IfStep : ∀st b b' c1 c2,
bstep st b b' →
cstep
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue : ∀st c1 c2,
cstep (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse : ∀st c1 c2,
cstep (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While : ∀st b c,
cstep
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
Local Open Scope imp.
Inductive cstep : (com * state) → (com * state) → Prop :=
| CS_AssStep : ∀st X a a',
astep st a a' →
cstep (CAss X a, st) (CAss X a', st)
| CS_Ass : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep : ∀st c1 c1' st' c2,
cstep (c1, st) (c1', st') →
cstep (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq : ∀st c2,
cstep (Skip ;; c2, st) (c2, st)
| CS_IfStep : ∀st b b' c1 c2,
bstep st b b' →
cstep
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue : ∀st c1 c2,
cstep (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse : ∀st c1 c2,
cstep (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While : ∀st b c,
cstep
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
In this definition, we use two small tricks:
For example,
Here is another example,
Similar to the small step semantics for expression evaluation, the multi-step
relation for cstep also has its own congruence property. We prove two typical
ones here.
- We use Skip as an "empty residue command".
- An assignment command reduces to Skip (and an updated
state).
- The sequencing command waits until its left-hand
subcommand has reduced to Skip, then throws it away so
that reduction can continue with the right-hand
subcommand.
- An assignment command reduces to Skip (and an updated
state).
- We reduce a While command by transforming it into a conditional followed by the same While.
X ::= 1;; Y ::= 2, st1
(* in which st1(Z) = 0 for all program variables Z *)
--> Skip;; Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Y ::= 2, st2
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
(* in which st1(Z) = 0 for all program variables Z *)
--> Skip;; Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Y ::= 2, st2
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
(* in which st1(Z) = 0 for all program variables Z *)
--> If (0 ≤ X)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> If (0 ≤ 0)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> If BTrue
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> X ::= 0 - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> X ::= -1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> Skip;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st2
(* in which st2(X) = -1 and
st2(Z) = 0 for all program variables Z *)
--> While (0 ≤ X) Do X ::= X - 1 EndWhile, st2
--> If (0 ≤ X)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> If (0 ≤ -1)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> If BFalse
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> Skip, st2
(* in which st1(Z) = 0 for all program variables Z *)
--> If (0 ≤ X)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> If (0 ≤ 0)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> If BTrue
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st1
--> X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> X ::= 0 - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> X ::= -1;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st1
--> Skip;; While (0 ≤ X) Do X ::= X - 1 EndWhile, st2
(* in which st2(X) = -1 and
st2(Z) = 0 for all program variables Z *)
--> While (0 ≤ X) Do X ::= X - 1 EndWhile, st2
--> If (0 ≤ X)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> If (0 ≤ -1)
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> If BFalse
Then X ::= X - 1;; While (0 ≤ X) Do X ::= X - 1 EndWhile
Else Skip
EndIf, st2
--> Skip, st2
Definition multi_cstep: com * state → com * state → Prop := clos_refl_trans cstep.
Theorem multi_congr_CSeq: ∀st1 c1 st1' c1' c2,
multi_cstep (c1, st1) (c1', st1') →
multi_cstep (c1 ;; c2, st1) (c1';; c2, st1').
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ (** Oops, Coq does not generate a proof goal as we expected. *)
Abort.
Theorem multi_congr_CSeq: ∀st1 c1 st1' c1' c2,
multi_cstep (c1, st1) (c1', st1') →
multi_cstep (c1 ;; c2, st1) (c1';; c2, st1').
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ (** Oops, Coq does not generate a proof goal as we expected. *)
Abort.
The problem here is, Coq's induction tactic on inductive predicates
requires that predicate takes only Coq variables as its argument. Any other
internal structures are not allowed, or else necessary information might be
lost. In the case above, we do induction over:
H: clos_refl_trans_n1 cstep (c1, st1) (c1', st1')
In this hypothesis, (c1, st1) and (c1', st1') are not simple Coq variables.
Coq provides remember tactic for necessary transitions.
Theorem multi_congr_CSeq: ∀st1 c1 st1' c1' c2,
multi_cstep (c1, st1) (c1', st1') →
multi_cstep (c1 ;; c2, st1) (c1';; c2, st1').
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
remember (c1, st1) as cst eqn:H0.
remember (c1', st1') as cst' eqn:H1.
multi_cstep (c1, st1) (c1', st1') →
multi_cstep (c1 ;; c2, st1) (c1';; c2, st1').
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
remember (c1, st1) as cst eqn:H0.
remember (c1', st1') as cst' eqn:H1.
These two commands say: use cst and cst' to represent those two
pairs. And use two equalities H0 and H1 to record this replacement.
revert c1 st1 c1' st1' H0 H1; induction H.
+ intros.
+ intros.
This branch corresponds to the case that
multi_cstep (c1, st1) (c1', st1')
is true because of reflexivity.
subst.
Remember, H1 actually says
pair c1 st1 = pair c1' st1'
and pair is a constructor for product type. Since all constructors are
injective, we can achieve c1 = c1' and st1 = st1'.
injection H1 as ?H ?H.
subst.
apply rtn1_refl.
+ intros.
subst.
apply rtn1_refl.
+ intros.
This branch corresponds to the case that
multi_cstep (c1, st1) (c1', st1')
is true because there exists another pair c1'', st'', such that
multi_cstep (c1, st1) (c1'', st1'')
cstep (c1'', st1'') (c1', st1')
holds.
cstep (c1'', st1'') (c1', st1')
subst.
destruct y as [c1'' st1''].
eapply rtn1_trans.
- apply CS_SeqStep.
exact H.
- apply IHclos_refl_trans_n1.
* reflexivity.
* reflexivity.
Qed.
destruct y as [c1'' st1''].
eapply rtn1_trans.
- apply CS_SeqStep.
exact H.
- apply IHclos_refl_trans_n1.
* reflexivity.
* reflexivity.
Qed.
This next example is about if-then-else commands.
Theorem multi_congr_CIf: ∀st b b' c1 c2,
multi_bstep st b b' →
multi_cstep
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st).
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply CS_IfStep.
exact H.
- exact IHclos_refl_trans_n1.
Qed.
multi_bstep st b b' →
multi_cstep
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st).
Proof.
intros.
unfold multi_cstep in H.
unfold multi_cstep.
apply Operators_Properties.clos_rt_rtn1_iff.
apply Operators_Properties.clos_rt_rtn1_iff in H.
induction H.
+ apply rtn1_refl.
+ eapply rtn1_trans.
- apply CS_IfStep.
exact H.
- exact IHclos_refl_trans_n1.
Qed.
Administrative Steps and Alternative Definitions
Inductive cstep_halt': com → Prop :=
| CH_Skip: cstep_halt' Skip
| CH_Seq: ∀c1 c2,
cstep_halt' c1 →
cstep_halt' c2 →
cstep_halt' (c1;; c2).
| CH_Skip: cstep_halt' Skip
| CH_Seq: ∀c1 c2,
cstep_halt' c1 →
cstep_halt' c2 →
cstep_halt' (c1;; c2).
In this definition, a program halts not only at Skip but at any sequential
combination of Skips.
Inductive cstep' : (com * state) → (com * state) → Prop :=
| CS_AssStep' : ∀st X a a',
astep st a a' →
cstep' (CAss X a, st) (CAss X a', st)
| CS_Ass' : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep' (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep' : ∀st c1 c1' st' c2,
cstep' (c1, st) (c1', st') →
cstep' (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq' : ∀st c1 c2 st' c2',
cstep_halt' c1 →
cstep' (c2, st) (c2', st') →
cstep' (c1 ;; c2, st) (c2', st') (* <- This is different. *)
| CS_IfStep' : ∀st b b' c1 c2,
bstep st b b' →
cstep'
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue' : ∀st c1 c2,
cstep' (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse' : ∀st c1 c2,
cstep' (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While' : ∀st b c,
cstep'
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
| CS_AssStep' : ∀st X a a',
astep st a a' →
cstep' (CAss X a, st) (CAss X a', st)
| CS_Ass' : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep' (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep' : ∀st c1 c1' st' c2,
cstep' (c1, st) (c1', st') →
cstep' (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq' : ∀st c1 c2 st' c2',
cstep_halt' c1 →
cstep' (c2, st) (c2', st') →
cstep' (c1 ;; c2, st) (c2', st') (* <- This is different. *)
| CS_IfStep' : ∀st b b' c1 c2,
bstep st b b' →
cstep'
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue' : ∀st c1 c2,
cstep' (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse' : ∀st c1 c2,
cstep' (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While' : ∀st b c,
cstep'
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
The main idea is: if the left side of a sequential composition only has
Skips, they should be removed in zero steps.
For example,
Another alternative choice is to eliminate extra Skips after every steps.
Here is the definition.
X ::= 1;; Y ::= 2, st1
(* in which st1(Z) = 0 for all program variables Z *)
--> Skip;; Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
(* in which st1(Z) = 0 for all program variables Z *)
--> Skip;; Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
Inductive cstep'' : (com * state) → (com * state) → Prop :=
| CS_AssStep'' : ∀st X a a',
astep st a a' →
cstep'' (CAss X a, st) (CAss X a', st)
| CS_Ass'' : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep'' (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep'' : ∀st c1 c1' st' c2,
cstep'' (c1, st) (c1', st') →
c1' ≠ Skip → (* <- This is different. *)
cstep'' (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq'' : ∀st c1 c2 st',
cstep'' (c1, st) (Skip, st') →
cstep'' (c1 ;; c2 , st) (c2, st') (* <- This is different. *)
| CS_IfStep'' : ∀st b b' c1 c2,
bstep st b b' →
cstep''
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue'' : ∀st c1 c2,
cstep'' (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse'' : ∀st c1 c2,
cstep'' (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While'' : ∀st b c,
cstep''
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
| CS_AssStep'' : ∀st X a a',
astep st a a' →
cstep'' (CAss X a, st) (CAss X a', st)
| CS_Ass'' : ∀st1 st2 X n,
st2 X = n →
(∀Y, X ≠ Y → st1 Y = st2 Y) →
cstep'' (CAss X (ANum n), st1) (Skip, st2)
| CS_SeqStep'' : ∀st c1 c1' st' c2,
cstep'' (c1, st) (c1', st') →
c1' ≠ Skip → (* <- This is different. *)
cstep'' (c1 ;; c2 , st) (c1' ;; c2, st')
| CS_Seq'' : ∀st c1 c2 st',
cstep'' (c1, st) (Skip, st') →
cstep'' (c1 ;; c2 , st) (c2, st') (* <- This is different. *)
| CS_IfStep'' : ∀st b b' c1 c2,
bstep st b b' →
cstep''
(If b Then c1 Else c2 EndIf, st)
(If b' Then c1 Else c2 EndIf, st)
| CS_IfTrue'' : ∀st c1 c2,
cstep'' (If BTrue Then c1 Else c2 EndIf, st) (c1, st)
| CS_IfFalse'' : ∀st c1 c2,
cstep'' (If BFalse Then c1 Else c2 EndIf, st) (c2, st)
| CS_While'' : ∀st b c,
cstep''
(While b Do c EndWhile, st)
(If b Then (c;; While b Do c EndWhile) Else Skip EndIf, st).
X ::= 1;; Y ::= 2, st1
(* in which st1(Z) = 0 for all program variables Z *)
--> Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
(* in which st1(Z) = 0 for all program variables Z *)
--> Y ::= 2, st2
(* in which st2(X) = 1 and
st2(Z) = 0 for all other program variables Z *)
--> Skip, st3
(* in which st3(X) = 1 and
st3(Y) = 2 and
st3(Z) = 0 for all other program variables Z *)
- Sequential composition with Skip,
- Empty loop body.
(* Mon Apr 15 16:05:07 UTC 2019 *)