
ImpCEvalFunAn Evaluation Function for Imp
xxxxxxxxxx
1
From Coq Require Import Lia.
2
From Coq Require Import Arith.Arith.
3
From Coq Require Import Arith.PeanoNat.
4
Import Nat.
5
From Coq Require Import Arith.EqNat.
6
From LF Require Import Imp Maps.
Here was our first try at an evaluation function for commands,
omitting while.
xxxxxxxxxx
16
7
Fixpoint ceval_step1 (st : state) (c : com) : state :=
8
match c with
9
| <{ skip }>
10
st
11
| <{ l := a1 }>
12
(l ! aeval st a1 ; st)
13
| <{ c1 ; c2 }>
14
let st' := ceval_step1 st c1 in
15
ceval_step1 st' c2
16
| <{ if b then c1 else c2 end }>
17
if (beval st b)
18
then ceval_step1 st c1
19
else ceval_step1 st c2
20
| <{ while b1 do c1 end }>
21
st (* bogus *)
22
end.
As we remarked in chapter Imp, in a traditional functional
programming language like ML or Haskell we could write the while
case as follows:
Thus, because it doesn't terminate on all inputs, the full version
of ceval_step1 cannot be written in Coq -- at least not without
one additional trick...
| while b1 do c1 end => if (beval st b1) then ceval_step1 st <{ c1; while b1 do c1 end }> else stCoq doesn't accept such a definition (Error: Cannot guess decreasing argument of fix) because the function we want to define is not guaranteed to terminate. Indeed, the changed ceval_step1 function applied to the loop program from Imp.v would never terminate. Since Coq is not just a functional programming language, but also a consistent logic, any potentially non-terminating function needs to be rejected. Here is an invalid(!) Coq program showing what would go wrong if Coq allowed non-terminating recursive functions:
Fixpoint loop_false (n : nat) : False := loop_false n.That is, propositions like False would become provable (e.g., loop_false 0 would be a proof of False), which would be a disaster for Coq's logical consistency.
A Step-Indexed Evaluator
xxxxxxxxxx
23
23
Fixpoint ceval_step2 (st : state) (c : com) (i : ) : state :=
24
match i with
25
| O empty_st
26
| S i'
27
match c with
28
| <{ skip }>
29
st
30
| <{ l := a1 }>
31
(l ! aeval st a1 ; st)
32
| <{ c1 ; c2 }>
33
let st' := ceval_step2 st c1 i' in
34
ceval_step2 st' c2 i'
35
| <{ if b then c1 else c2 end }>
36
if (beval st b)
37
then ceval_step2 st c1 i'
38
else ceval_step2 st c2 i'
39
| <{ while b1 do c1 end }>
40
if (beval st b1)
41
then let st' := ceval_step2 st c1 i' in
42
ceval_step2 st' c i'
43
else st
44
end
45
end.
Note: It is tempting to think that the index i here is
counting the "number of steps of evaluation." But if you look
closely you'll see that this is not the case: for example, in the
rule for sequencing, the same i is passed to both recursive
calls. Understanding the exact way that i is treated will be
important in the proof of ceval__ceval_step, which is given as
an exercise below.
One thing that is not so nice about this evaluator is that we
can't tell, from its result, whether it stopped because the
program terminated normally or because it ran out of gas. Our
next version returns an option state instead of just a state,
so that we can distinguish between normal and abnormal
termination.
xxxxxxxxxx
28
46
Fixpoint ceval_step3 (st : state) (c : com) (i : )
47
: option state :=
48
match i with
49
| O None
50
| S i'
51
match c with
52
| <{ skip }>
53
Some st
54
| <{ l := a1 }>
55
Some (l ! aeval st a1 ; st)
56
| <{ c1 ; c2 }>
57
match (ceval_step3 st c1 i') with
58
| Some st' ceval_step3 st' c2 i'
59
| None None
60
end
61
| <{ if b then c1 else c2 end }>
62
if (beval st b)
63
then ceval_step3 st c1 i'
64
else ceval_step3 st c2 i'
65
| <{ while b1 do c1 end }>
66
if (beval st b1)
67
then match (ceval_step3 st c1 i') with
68
| Some st' ceval_step3 st' c i'
69
| None None
70
end
71
else Some st
72
end
73
end.
We can improve the readability of this version by introducing a
bit of auxiliary notation to hide the plumbing involved in
repeatedly matching against optional states.
xxxxxxxxxx
119
74
Notation "'LETOPT' x <== e1 'IN' e2"
75
:= (match e1 with
76
| Some x e2
77
| None None
78
end)
79
(right associativity, at level 60).
80
Fixpoint ceval_step (st : state) (c : com) (i : )
81
: option state :=
82
match i with
83
| O None
84
| S i'
85
match c with
86
| <{ skip }>
87
Some st
88
| <{ l := a1 }>
89
Some (l ! aeval st a1 ; st)
90
| <{ c1 ; c2 }>
91
LETOPT st' <== ceval_step st c1 i' IN
92
ceval_step st' c2 i'
93
| <{ if b then c1 else c2 end }>
94
if (beval st b)
95
then ceval_step st c1 i'
96
else ceval_step st c2 i'
97
| <{ while b1 do c1 end }>
98
if (beval st b1)
99
then LETOPT st' <== ceval_step st c1 i' IN
100
ceval_step st' c i'
101
else Some st
102
end
103
end.
104
Definition test_ceval (st:state) (c:com) :=
105
match ceval_step st c 500 with
106
| None None
107
| Some st Some (st X, st Y, st Z)
108
end.
109
Example example_test_ceval :
110
test_ceval empty_st
111
112
<{ X := 2;
113
if (X 1)
114
then Y := 3
115
else Z := 4
116
end }>
117
118
= Some (2, 0, 4).
119
Proof. reflexivity. Qed.
Exercise: 2 stars, standard, especially useful (pup_to_n)
Write an Imp program that sums the numbers from 1 to X (inclusive: 1 + 2 + ... + X) in the variable Y. Make sure your solution satisfies the test that follows.xxxxxxxxxx
128
120
Definition pup_to_n : com
121
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.
122
Example pup_to_n_1 :
123
test_ceval (X ! 5) pup_to_n
124
= Some (0, 15, 0).
125
(* FILL IN HERE *) Admitted.
126
(*
127
Proof. reflexivity. Qed.
128
*)
Exercise: 2 stars, standard, optional (peven)
Write an Imp program that sets Z to 0 if X is even and sets Z to 1 otherwise. Use test_ceval to test your program.xxxxxxxxxx
129
129
(* FILL IN HERE *)
Relational vs. Step-Indexed Evaluation
xxxxxxxxxx
179
130
Theorem ceval_stepceval: ∀ c st st',
131
( i, ceval_step st c i = Some st')
132
st =[ c ] st'.
133
134
135
Proof.
136
intros c st st' H.
137
inversion H as [i E].
138
clear H.
139
generalize dependent st'.
140
generalize dependent st.
141
generalize dependent c.
142
induction i as [| i' ].
143
- (* i = 0 -- contradictory *)
144
intros c st st' H. discriminate H.
145
- (* i = S i' *)
146
intros c st st' H.
147
destruct c;
148
simpl in H; inversion H; subst; clear H.
149
+ (* skip *) apply E_Skip.
150
+ (* := *) apply E_Ass. reflexivity.
151
+ (* ; *)
152
destruct (ceval_step st c1 i') eqn:Heqr1.
153
* (* Evaluation of r1 terminates normally *)
154
apply E_Seq with s.
155
apply IHi'. rewrite Heqr1. reflexivity.
156
apply IHi'. simpl in H1. assumption.
157
* (* Otherwise -- contradiction *)
158
discriminate H1.
159
+ (* if *)
160
destruct (beval st b) eqn:Heqr.
161
* (* r = true *)
162
apply E_IfTrue. rewrite Heqr. reflexivity.
163
apply IHi'. assumption.
164
* (* r = false *)
165
apply E_IfFalse. rewrite Heqr. reflexivity.
166
apply IHi'. assumption.
167
+ (* while *) destruct (beval st b) eqn :Heqr.
168
* (* r = true *)
169
destruct (ceval_step st c i') eqn:Heqr1.
170
{ (* r1 = Some s *)
171
apply E_WhileTrue with s. rewrite Heqr.
172
reflexivity.
173
apply IHi'. rewrite Heqr1. reflexivity.
174
apply IHi'. simpl in H1. assumption. }
175
{ (* r1 = None *) discriminate H1. }
176
* (* r = false *)
177
injection H1 as H2. rewrite H2.
178
apply E_WhileFalse. apply Heqr. Qed.
179
Exercise: 4 stars, standard (ceval_step__ceval_inf)
Write an informal proof of ceval_step__ceval, following the usual template. (The template for case analysis on an inductively defined value should look the same as for induction, except that there is no induction hypothesis.) Make your proof communicate the main ideas to a human reader; do not simply transcribe the steps of the formal proof.xxxxxxxxxx
182
180
(* FILL IN HERE *)
181
(* Do not modify the following line: *)
182
Definition manual_grade_for_ceval_stepceval_inf : option (*string) := None.
xxxxxxxxxx
223
183
Theorem ceval_step_more: ∀ i1 i2 st st' c,
184
i1 i2
185
ceval_step st c i1 = Some st'
186
ceval_step st c i2 = Some st'.
187
Proof.
188
induction i1 as [|i1']; intros i2 st st' c Hle Hceval.
189
- (* i1 = 0 *)
190
simpl in Hceval. discriminate Hceval.
191
- (* i1 = S i1' *)
192
destruct i2 as [|i2']. inversion Hle.
193
assert (Hle': i1' i2') by lia.
194
destruct c.
195
+ (* skip *)
196
simpl in Hceval. inversion Hceval.
197
reflexivity.
198
+ (* := *)
199
simpl in Hceval. inversion Hceval.
200
reflexivity.
201
+ (* ; *)
202
simpl in Hceval. simpl.
203
destruct (ceval_step st c1 i1') eqn:Heqst1'o.
204
* (* st1'o = Some *)
205
apply (IHi1' i2') in Heqst1'o; try assumption.
206
rewrite Heqst1'o. simpl. simpl in Hceval.
207
apply (IHi1' i2') in Hceval; try assumption.
208
* (* st1'o = None *)
209
discriminate Hceval.
210
+ (* if *)
211
simpl in Hceval. simpl.
212
destruct (beval st b); apply (IHi1' i2') in Hceval;
213
assumption.
214
+ (* while *)
215
simpl in Hceval. simpl.
216
destruct (beval st b); try assumption.
217
destruct (ceval_step st c i1') eqn: Heqst1'o.
218
* (* st1'o = Some *)
219
apply (IHi1' i2') in Heqst1'o; try assumption.
220
rewrite Heqst1'o. simpl. simpl in Hceval.
221
apply (IHi1' i2') in Hceval; try assumption.
222
* (* i1'o = None *)
223
simpl in Hceval. discriminate Hceval. Qed.
Exercise: 3 stars, standard, especially useful (ceval__ceval_step)
Finish the following proof. You'll need ceval_step_more in a few places, as well as some basic facts about ≤ and plus.xxxxxxxxxx
230
224
Theorem cevalceval_step: ∀ c st st',
225
st =[ c ] st'
226
i, ceval_step st c i = Some st'.
227
Proof.
228
intros c st st' Hce.
229
induction Hce.
230
(* FILL IN HERE *) Admitted.
xxxxxxxxxx
237
231
Theorem ceval_and_ceval_step_coincide: ∀ c st st',
232
st =[ c ] st'
233
i, ceval_step st c i = Some st'.
234
Proof.
235
intros c st st'.
236
split. apply cevalceval_step. apply ceval_stepceval.
237
Qed.
Determinism of Evaluation Again
xxxxxxxxxx
257
238
Theorem ceval_deterministic' : ∀ c st st1 st2,
239
st =[ c ] st1
240
st =[ c ] st2
241
st1 = st2.
242
243
244
Proof.
245
intros c st st1 st2 He1 He2.
246
apply cevalceval_step in He1.
247
apply cevalceval_step in He2.
248
inversion He1 as [i1 E1].
249
inversion He2 as [i2 E2].
250
apply ceval_step_more with (i2 := i1 + i2) in E1.
251
apply ceval_step_more with (i2 := i1 + i2) in E2.
252
rewrite E1 in E2. inversion E2. reflexivity.
253
lia. lia. Qed.
254
255
256
257
(* 2021-03-18 17:23 *)