-
Notifications
You must be signed in to change notification settings - Fork 108
/
L2Opt.thy
341 lines (299 loc) · 13.8 KB
/
L2Opt.thy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
(*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*)
theory L2Opt
imports L2Defs L2Peephole
begin
(* Flow-sensitive simplification rules for L2 programs. *)
named_theorems L2flow
(*
* The monads "A" and "B" are equivalent under precondition "P".
* Additionally, under this precondition, they always leave the
* postcondition "Q" (normally) or "E" (if an exception occurs).
*)
definition
"monad_equiv P A B Q E \<equiv> (\<forall>s. P s \<longrightarrow> A s = B s) \<and> \<lbrace> P \<rbrace> A \<lbrace> Q \<rbrace>, \<lbrace> E \<rbrace>"
lemma monad_equivI [intro]:
"\<lbrakk> \<And>s. P s \<Longrightarrow> A s = B s; \<lbrace> P \<rbrace> A \<lbrace> Q \<rbrace>, \<lbrace> E \<rbrace> \<rbrakk> \<Longrightarrow> monad_equiv P A B Q E"
apply (clarsimp simp: monad_equiv_def)
done
lemma monad_equiv_eqI [intro]:
"\<lbrakk> \<lbrace> P \<rbrace> A \<lbrace> Q \<rbrace>, \<lbrace> E \<rbrace> \<rbrakk> \<Longrightarrow> monad_equiv P A A Q E"
apply (clarsimp simp: monad_equiv_def)
done
lemma monad_equiv_eq:
"monad_equiv (\<lambda>_. True) A B X Y \<Longrightarrow> A = B"
apply (rule ext)
apply (clarsimp simp: monad_equiv_def)
done
lemma monad_equiv_triv [L2flow]:
"monad_equiv P A A (\<lambda>_ _. \<exists>s. P s) (\<lambda>_ _. \<exists>s. P s)"
apply rule
apply wp
apply force
done
lemma monad_equiv_symmetric:
"monad_equiv P A B X Y = monad_equiv P B A X Y"
apply (clarsimp simp: monad_equiv_def validE_def2 Ball_def split: sum.splits)
apply force
done
lemma monad_equivD: "\<lbrakk> monad_equiv P A B R E; P s \<rbrakk> \<Longrightarrow> A s = B s"
apply (clarsimp simp: monad_equiv_def)
done
(*
* Show that under condition "P", the values "A" and "B" are equal.
*
* We use this to simplify expressions inside our monads in a (somewhat)
* controlled fashion.
*)
definition "simp_expr P A B \<equiv> P \<longrightarrow> A = B"
lemma simp_expr_triv: "simp_expr P A A"
apply (clarsimp simp: simp_expr_def)
done
lemma simp_expr_P_cong:
"\<lbrakk> P = P' \<rbrakk> \<Longrightarrow> simp_expr P A B = simp_expr P' A B"
apply (clarsimp simp: simp_expr_def)
done
lemma simp_expr_rhs_cong [cong]:
"\<lbrakk> P = P'; P' \<Longrightarrow> B = B' \<rbrakk> \<Longrightarrow> simp_expr P A B = simp_expr P' A B'"
apply (clarsimp simp: simp_expr_def simp_implies_def)
done
lemma simp_expr_weaken:
"\<lbrakk> simp_expr P A B; Q \<Longrightarrow> P \<rbrakk> \<Longrightarrow> simp_expr Q A B"
apply (clarsimp simp: simp_expr_def)
done
(*
* Monad simplification rules.
*
* When solving "monad_equiv P A B R E", the l2_opt tactics assume that P is concrete;
* to ensure this, monad_equiv rules should result in R being instantiated.
* See e.g. monad_equiv_unreachable where we have to constrain the rule.
*)
lemma monad_equiv_gets [L2flow]:
"simp_expr True v v' \<Longrightarrow> monad_equiv P (L2_gets (\<lambda>s. v s) n) (L2_gets (\<lambda>s. v' s) n)
(\<lambda>r s. P s \<and> r = v' s) (\<lambda>_ _. False)"
apply rule
apply (clarsimp simp: L2_defs simp_expr_def)+
apply wpsimp
done
lemma monad_equiv_throw [L2flow]:
"simp_expr True v v' \<Longrightarrow>
monad_equiv P (L2_throw v n) (L2_throw v' n) (\<lambda>_ _. False) (\<lambda>r s. P s \<and> r = v')"
apply (clarsimp simp: monad_equiv_def L2_defs simp_expr_def)
apply wp
apply force
done
lemma monad_equiv_guard:
"\<lbrakk> \<And>s. simp_expr (P s) (G s) (G' s) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_guard (\<lambda>s. G s)) (L2_guard (\<lambda>s. G' s)) (\<lambda>r s. P s \<and> G' s \<and> r = ()) (\<lambda>_ _. False)"
apply (clarsimp simp: monad_equiv_def L2_defs simp_expr_def)
apply rule
apply (clarsimp simp: liftE_def guard_def bind_def in_return snd_return)
apply wp
apply force
done
(* We use this weaker form of guard simplification to prevent bound
* variables being expanded inside of guard statements. *)
lemma monad_equiv_guard' [L2flow]:
"\<lbrakk> \<And>s. simp_expr True (G s) (G' s) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_guard (\<lambda>s. G s)) (L2_guard (\<lambda>s. G' s)) (\<lambda>r s. P s \<and> G' s \<and> r = ()) (\<lambda>_ _. False)"
apply (rule monad_equiv_guard)
apply (rule simp_expr_weaken)
apply assumption
apply simp
done
lemma monad_equiv_guard_False [L2flow]:
"\<lbrakk> \<And>s. simp_expr (P s) False (G s) \<rbrakk>
\<Longrightarrow> monad_equiv P (L2_guard G) (L2_fail) (\<lambda>_ _. False) (\<lambda>_ _. False)"
apply (monad_eq simp: L2_defs monad_equiv_def simp_expr_def validE_def2)
done
lemma monad_equiv_guard_True [L2flow]:
"\<lbrakk> \<And>s. simp_expr (P s) True (G s) \<rbrakk>
\<Longrightarrow> monad_equiv P (L2_guard G) L2_skip (\<lambda>r s. P s \<and> r = ()) (\<lambda>_ _. False)"
apply (auto simp: L2_defs simp_expr_def guard_def liftE_def return_def returnOk_def bind_def validE_def valid_def)
done
lemma monad_equiv_guard_conj [L2flow]:
"\<lbrakk> monad_equiv P (L2_guard G1) G1' R1 E1;
monad_equiv (\<lambda>s. R1 () s) (L2_guard G2) G2' R2 E2 \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_guard (\<lambda>s. G1 s \<and> G2 s)) (L2_seq G1' (\<lambda>_. G2')) (\<lambda>r s. R2 () s) (\<lambda>_ _. False)"
apply (subst (asm) (1 2) monad_equiv_symmetric)
apply (subst monad_equiv_symmetric)
apply rule
apply (monad_eq simp: L2_defs monad_equiv_def validE_def2 Bex_def Ball_def split: sum.splits)
apply fast
apply (monad_eq simp: monad_equiv_def L2_defs validE_def2 Ball_def split: sum.splits)
apply fast
done
lemma monad_equiv_unknown [L2flow]:
"monad_equiv P (L2_unknown name) (L2_unknown name) (\<lambda>r s. P s) (\<lambda>_ _. False)"
apply (clarsimp simp: monad_equiv_def L2_defs)
apply wp
apply force
done
lemma monad_equiv_modify [L2flow]:
"\<lbrakk> \<And>s. simp_expr True (m s) (m' s) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_modify (\<lambda>s. m s)) (L2_modify (\<lambda>s. m' s)) (\<lambda>r s'. \<exists>s. P s \<and> m' s = s' \<and> r = ()) (\<lambda>_ _. False)"
apply rule
apply (clarsimp simp: L2_defs simp_expr_def liftE_def modify_def put_def get_def bind_def)
apply (clarsimp simp: L2_defs simp_expr_def)
apply wp
apply force
done
lemma monad_equiv_spec [L2flow]:
"\<lbrakk> \<And>s s'. simp_expr True ((s, s') \<in> S) (S' s s') \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_spec S) (L2_spec ({(s, s'). S' s s'})) (\<lambda>r s. \<exists>s. P s) (\<lambda>_ _. False)"
apply rule
apply (clarsimp simp: L2_defs simp_expr_def liftE_def spec_def bind_def)
apply (clarsimp simp: L2_defs)
apply wp
apply force
done
lemma monad_equiv_fail [L2flow]:
"monad_equiv P L2_fail L2_fail (\<lambda>_ _. False) (\<lambda>_ _. False)"
apply (clarsimp simp: monad_equiv_def L2_defs)
done
lemma monad_equiv_condition [L2flow]:
"\<lbrakk> \<And>s. simp_expr True (C s) (C' s);
monad_equiv (\<lambda>s. P s \<and> C' s) L L' QL EL;
monad_equiv (\<lambda>s. P s \<and> \<not> C' s) R R' QR ER \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_condition (\<lambda>s. C s) L R) (L2_condition (\<lambda>s. C' s) L' R')
(\<lambda>r s. \<exists>s. P s) \<comment> \<open>Deliberately weak to avoid exponential growth.\<close>
(\<lambda>r s. \<exists>s. P s)"
apply rule
apply (monad_eq simp: L2_defs monad_equiv_def simp_expr_def split: condition_splits)
apply (monad_eq simp: L2_defs monad_equiv_def validE_def2 split: condition_splits sum.splits)
apply force
done
lemma monad_equiv_condition_True [L2flow]:
"\<lbrakk> \<And>s. simp_expr (P s) (C s) True;
monad_equiv P L L' QL EL \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_condition C L R) L' QL EL"
unfolding L2_defs condition_def
apply (monad_eq simp: simp_expr_def monad_equiv_def validE_def2 Ball_def split: sum.splits)
done
lemma monad_equiv_condition_False [L2flow]:
"\<lbrakk> \<And>s. simp_expr (P s) (C s) False;
monad_equiv P R R' QR ER \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_condition C L R) R' QR ER"
unfolding L2_defs condition_def
apply (monad_eq simp: simp_expr_def monad_equiv_def validE_def2 Ball_def split: sum.splits)
done
(* C-parser sometimes generates boolean expressions like
if P then (if P then 1 else 0) else Q
This simplifies the branches. *)
lemma monad_equiv_gets_if [L2flow]:
"\<lbrakk> \<And>s. simp_expr (P s) True (b s) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_gets (\<lambda>s. if (b s) then L else R) f)
(L2_gets (\<lambda>s. L) f) (%r s. P s) (\<lambda>r s. False)"
"\<lbrakk> \<And>s. simp_expr (P s) False (b s) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_gets (\<lambda>s. if (b s) then L else R) f)
(L2_gets (\<lambda>s. R) f) (%r s. P s) (\<lambda>r s. False)"
apply (monad_eq simp: L2_defs simp_expr_def monad_equiv_def
validE_def valid_def split: sum.splits)+
done
lemma monad_equiv_seq [L2flow]:
"\<lbrakk> monad_equiv P A A' Q E;
\<And>x. monad_equiv (Q x) (B x) (B' x) (R x) (E2 x) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_seq A (\<lambda>x. B x)) (L2_seq A' (\<lambda>x. B' x)) (\<lambda>r s. \<exists>r'. R r' r s) (\<lambda>r s. \<exists>s. P s)"
apply rule
apply (clarsimp simp: monad_equiv_def L2_defs simp_expr_def)
apply (rule bindE_apply_cong)
apply simp
apply (clarsimp simp: validE_def valid_def)
apply force
apply (clarsimp simp: monad_equiv_def L2_defs
validE_def valid_def in_bindE simp_expr_def split: sum.splits)
apply (erule allE, erule (1) impE)+
apply fastforce
done
lemma monad_equiv_catch [L2flow]:
"\<lbrakk> monad_equiv P A A' Q E;
\<And>x. monad_equiv (E x) (B x) (B' x) (Q' x) (E2 x) \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_catch A (\<lambda>x. B x)) (L2_catch A' (\<lambda>x. B' x)) (\<lambda>r s. \<exists>s. P s) (\<lambda>r s. \<exists>r'. E2 r' r s)"
apply rule
apply atomize
apply (clarsimp simp: simp_expr_def L2_defs monad_equiv_def)
apply (erule allE, erule impE, assumption)
apply (clarsimp simp: validE_def2 split: sum.splits)
apply (erule allE, erule impE, assumption)
apply (rule monad_state_eqI)
apply (clarsimp simp: in_handleE')
apply force
apply (clarsimp simp: in_handleE')
apply force
apply (fastforce simp: snd_handleE')
apply (clarsimp simp: monad_equiv_def L2_defs
validE_def valid_def simp_expr_def in_handleE' split: sum.splits)
apply (erule allE, erule (1) impE)+
apply fastforce
done
lemma monad_equiv_cong:
"\<lbrakk> \<And>s. P s = P' s;
\<And>s. P s \<Longrightarrow> A s = A' s;
\<And>s. P s \<Longrightarrow> B s = B' s;
\<And>s s' r. P s \<Longrightarrow> Q r s' = Q' r s';
\<And>s s' r. P s \<Longrightarrow> R r s' = R' r s' \<rbrakk> \<Longrightarrow>
monad_equiv P A B Q R = monad_equiv P' A' B' Q' R'"
apply atomize
apply (clarsimp simp: monad_equiv_def validE_def valid_def split: sum.splits)
apply (rule iffI)
apply clarsimp
apply fastforce
apply clarsimp
apply fastforce
done
lemma monad_equiv_while [L2flow]:
assumes cond_simp: "\<And>s r. simp_expr True (c r s) (c' r s)"
assumes body_equiv: "\<And>r. monad_equiv (\<lambda>s. (\<exists>s'. P s') \<and> c' r s) (B r) (B' r) (Q r) (E r)"
assumes init_simp: "\<And>s r. simp_expr True x x'"
shows "monad_equiv P (L2_while (\<lambda>r s. c r s) B x n) (L2_while (\<lambda>r s. c' r s) B' x' n) (\<lambda>r s. \<not> c' r s \<and> (\<exists>x. P x)) (\<lambda>r s. \<exists>x. E x r s)"
apply (insert cond_simp [unfolded simp_expr_def] init_simp [unfolded simp_expr_def])
apply rule
apply (clarsimp simp: L2_while_def)
apply (rule whileLoopE_cong [THEN fun_cong, THEN fun_cong])
apply force
apply (cut_tac r=r in body_equiv)
apply (clarsimp simp: monad_equiv_def)
apply (erule allE, erule impE, auto)[1]
apply simp
apply (clarsimp simp: L2_while_def)
apply (rule validE_whileLoopE [where I="\<lambda>r s. \<exists>s. P s"])
apply force
apply (cut_tac r=r in body_equiv)
apply (clarsimp simp: validE_def valid_def monad_equiv_def split: sum.splits)
apply blast
apply simp
done
lemma monad_equiv_recguard [L2flow]:
"\<lbrakk> monad_equiv P B B' Q E \<rbrakk> \<Longrightarrow>
monad_equiv P (L2_recguard a B) (L2_recguard a B') Q E"
apply rule
apply (clarsimp simp: L2_recguard_def monad_equiv_def valid_def validE_def
split: sum.splits condition_splits)
apply (clarsimp simp: L2_recguard_def monad_equiv_def valid_def validE_def in_fail
split: sum.splits condition_splits)
done
lemma monad_equiv_unreachable' [L2flow]:
"monad_equiv (\<lambda>_. False) L (L2_gets (\<lambda>_. undefined) [''L2Opt_internal_var'']) Q R"
by (simp add: monad_equiv_def)
(* avoid leaving schematic Q in goal *)
lemma monad_equiv_unreachable [L2flow]:
"monad_equiv (\<lambda>_. False) L (L2_gets (\<lambda>_. undefined) [''L2Opt_internal_var'']) (\<lambda>_ _. False) R"
by (rule monad_equiv_unreachable')
lemma monad_equiv_split [L2flow]:
"\<lbrakk> \<And>a b. monad_equiv (P (a, b)) (X a b) (Y a b) (Q a b) (E a b) \<rbrakk> \<Longrightarrow>
monad_equiv (P x) (case x of (a, b) \<Rightarrow> X a b) (case x of (a, b) \<Rightarrow> Y a b)
(case x of (a, b) \<Rightarrow> Q a b) (case x of (a, b) \<Rightarrow> E a b)"
apply (clarsimp simp: monad_equiv_def validE_def valid_def split_def)
done
lemma simp_expr_solve_constant: "\<lbrakk> A \<Longrightarrow> B = C \<rbrakk> \<Longrightarrow> simp_expr A B C"
by (clarsimp simp: simp_expr_def)
lemma monad_equiv_weaken_pre':
"\<lbrakk> \<And>s. P' s \<Longrightarrow> P s; monad_equiv P L R Q E \<rbrakk> \<Longrightarrow> monad_equiv P' L R Q E"
by (fastforce simp: monad_equiv_def validE_def valid_def)
lemma monad_equiv_weaken_pre'':
"\<lbrakk> P' \<equiv> P; monad_equiv P L R Q E \<rbrakk> \<Longrightarrow> monad_equiv P' L R Q E"
by (fastforce simp: monad_equiv_def validE_def valid_def)
end