34 constdefs |
34 constdefs |
35 (** Release some client_tokens **) |
35 (** Release some client_tokens **) |
36 |
36 |
37 client_rel_act ::i |
37 client_rel_act ::i |
38 "client_rel_act == |
38 "client_rel_act == |
39 {<s,t> \\<in> state*state. |
39 {<s,t> \<in> state*state. |
40 \\<exists>nrel \\<in> nat. nrel = length(s`rel) & |
40 \<exists>nrel \<in> nat. nrel = length(s`rel) & |
41 t = s(rel:=(s`rel)@[nth(nrel, s`giv)]) & |
41 t = s(rel:=(s`rel)@[nth(nrel, s`giv)]) & |
42 nrel < length(s`giv) & |
42 nrel < length(s`giv) & |
43 nth(nrel, s`ask) le nth(nrel, s`giv)}" |
43 nth(nrel, s`ask) \<le> nth(nrel, s`giv)}" |
44 |
44 |
45 (** Choose a new token requirement **) |
45 (** Choose a new token requirement **) |
46 (** Including t=s suppresses fairness, allowing the non-trivial part |
46 (** Including t=s suppresses fairness, allowing the non-trivial part |
47 of the action to be ignored **) |
47 of the action to be ignored **) |
48 |
48 |
49 client_tok_act :: i |
49 client_tok_act :: i |
50 "client_tok_act == {<s,t> \\<in> state*state. t=s | |
50 "client_tok_act == {<s,t> \<in> state*state. t=s | |
51 t = s(tok:=succ(s`tok mod NbT))}" |
51 t = s(tok:=succ(s`tok mod NbT))}" |
52 |
52 |
53 client_ask_act :: i |
53 client_ask_act :: i |
54 "client_ask_act == {<s,t> \\<in> state*state. t=s | (t=s(ask:=s`ask@[s`tok]))}" |
54 "client_ask_act == {<s,t> \<in> state*state. t=s | (t=s(ask:=s`ask@[s`tok]))}" |
55 |
55 |
56 client_prog :: i |
56 client_prog :: i |
57 "client_prog == |
57 "client_prog == |
58 mk_program({s \\<in> state. s`tok le NbT & s`giv = Nil & |
58 mk_program({s \<in> state. s`tok \<le> NbT & s`giv = Nil & |
59 s`ask = Nil & s`rel = Nil}, |
59 s`ask = Nil & s`rel = Nil}, |
60 {client_rel_act, client_tok_act, client_ask_act}, |
60 {client_rel_act, client_tok_act, client_ask_act}, |
61 \\<Union>G \\<in> preserves(lift(rel)) Int |
61 \<Union>G \<in> preserves(lift(rel)) Int |
62 preserves(lift(ask)) Int |
62 preserves(lift(ask)) Int |
63 preserves(lift(tok)). Acts(G))" |
63 preserves(lift(tok)). Acts(G))" |
|
64 |
|
65 |
|
66 declare type_assumes [simp] default_val_assumes [simp] |
|
67 (* This part should be automated *) |
|
68 |
|
69 (*????MOVE UP*) |
|
70 method_setup constrains = {* |
|
71 Method.ctxt_args (fn ctxt => |
|
72 Method.METHOD (fn facts => |
|
73 gen_constrains_tac (Classical.get_local_claset ctxt, |
|
74 Simplifier.get_local_simpset ctxt) 1)) *} |
|
75 "for proving safety properties" |
|
76 |
|
77 (*For using "disjunction" (union over an index set) to eliminate a variable. |
|
78 ????move way up*) |
|
79 lemma UN_conj_eq: "\<forall>s\<in>state. f(s) \<in> A |
|
80 ==> (\<Union>k\<in>A. {s\<in>state. P(s) & f(s) = k}) = {s\<in>state. P(s)}" |
|
81 by blast |
|
82 |
|
83 lemma ask_value_type [simp,TC]: "s \<in> state ==> s`ask \<in> list(nat)" |
|
84 apply (unfold state_def) |
|
85 apply (drule_tac a = ask in apply_type, auto) |
|
86 done |
|
87 |
|
88 lemma giv_value_type [simp,TC]: "s \<in> state ==> s`giv \<in> list(nat)" |
|
89 apply (unfold state_def) |
|
90 apply (drule_tac a = giv in apply_type, auto) |
|
91 done |
|
92 |
|
93 lemma rel_value_type [simp,TC]: "s \<in> state ==> s`rel \<in> list(nat)" |
|
94 apply (unfold state_def) |
|
95 apply (drule_tac a = rel in apply_type, auto) |
|
96 done |
|
97 |
|
98 lemma tok_value_type [simp,TC]: "s \<in> state ==> s`tok \<in> nat" |
|
99 apply (unfold state_def) |
|
100 apply (drule_tac a = tok in apply_type, auto) |
|
101 done |
|
102 |
|
103 (** The Client Program **) |
|
104 |
|
105 lemma client_type [simp,TC]: "client_prog \<in> program" |
|
106 apply (unfold client_prog_def) |
|
107 apply (simp (no_asm)) |
|
108 done |
|
109 |
|
110 declare client_prog_def [THEN def_prg_Init, simp] |
|
111 declare client_prog_def [THEN def_prg_AllowedActs, simp] |
|
112 ML |
|
113 {* |
|
114 program_defs_ref := [thm"client_prog_def"] |
|
115 *} |
|
116 |
|
117 declare client_rel_act_def [THEN def_act_simp, simp] |
|
118 declare client_tok_act_def [THEN def_act_simp, simp] |
|
119 declare client_ask_act_def [THEN def_act_simp, simp] |
|
120 |
|
121 lemma client_prog_ok_iff: |
|
122 "\<forall>G \<in> program. (client_prog ok G) <-> |
|
123 (G \<in> preserves(lift(rel)) & G \<in> preserves(lift(ask)) & |
|
124 G \<in> preserves(lift(tok)) & client_prog \<in> Allowed(G))" |
|
125 by (auto simp add: ok_iff_Allowed client_prog_def [THEN def_prg_Allowed]) |
|
126 |
|
127 lemma client_prog_preserves: |
|
128 "client_prog:(\<Inter>x \<in> var-{ask, rel, tok}. preserves(lift(x)))" |
|
129 apply (rule Inter_var_DiffI, force) |
|
130 apply (rule ballI) |
|
131 apply (rule preservesI, constrains, auto) |
|
132 done |
|
133 |
|
134 |
|
135 lemma preserves_lift_imp_stable: |
|
136 "G \<in> preserves(lift(ff)) ==> G \<in> stable({s \<in> state. P(s`ff)})"; |
|
137 apply (drule preserves_imp_stable) |
|
138 apply (simp add: lift_def) |
|
139 done |
|
140 |
|
141 lemma preserves_imp_prefix: |
|
142 "G \<in> preserves(lift(ff)) |
|
143 ==> G \<in> stable({s \<in> state. \<langle>k, s`ff\<rangle> \<in> prefix(nat)})"; |
|
144 by (erule preserves_lift_imp_stable) |
|
145 |
|
146 (*Safety property 1: ask, rel are increasing: (24) *) |
|
147 lemma client_prog_Increasing_ask_rel: |
|
148 "client_prog: program guarantees Incr(lift(ask)) Int Incr(lift(rel))" |
|
149 apply (unfold guar_def) |
|
150 apply (auto intro!: increasing_imp_Increasing |
|
151 simp add: client_prog_ok_iff increasing_def preserves_imp_prefix) |
|
152 apply (constrains, force, force)+ |
|
153 done |
|
154 |
|
155 declare nth_append [simp] append_one_prefix [simp] |
|
156 |
|
157 lemma NbT_pos2: "0<NbT" |
|
158 apply (cut_tac NbT_pos) |
|
159 apply (rule Ord_0_lt, auto) |
|
160 done |
|
161 |
|
162 (*Safety property 2: the client never requests too many tokens. |
|
163 With no Substitution Axiom, we must prove the two invariants simultaneously. *) |
|
164 |
|
165 lemma ask_Bounded_lemma: |
|
166 "[| client_prog ok G; G \<in> program |] |
|
167 ==> client_prog Join G \<in> |
|
168 Always({s \<in> state. s`tok \<le> NbT} Int |
|
169 {s \<in> state. \<forall>elt \<in> set_of_list(s`ask). elt \<le> NbT})" |
|
170 apply (rotate_tac -1) |
|
171 apply (auto simp add: client_prog_ok_iff) |
|
172 apply (rule invariantI [THEN stable_Join_Always2], force) |
|
173 prefer 2 |
|
174 apply (fast intro: stable_Int preserves_lift_imp_stable, constrains) |
|
175 apply (auto dest: ActsD) |
|
176 apply (cut_tac NbT_pos) |
|
177 apply (rule NbT_pos2 [THEN mod_less_divisor]) |
|
178 apply (auto dest: ActsD preserves_imp_eq simp add: set_of_list_append) |
|
179 done |
|
180 |
|
181 (* Export version, with no mention of tok in the postcondition, but |
|
182 unfortunately tok must be declared local.*) |
|
183 lemma client_prog_ask_Bounded: |
|
184 "client_prog \<in> program guarantees |
|
185 Always({s \<in> state. \<forall>elt \<in> set_of_list(s`ask). elt \<le> NbT})" |
|
186 apply (rule guaranteesI) |
|
187 apply (erule ask_Bounded_lemma [THEN Always_weaken], auto) |
|
188 done |
|
189 |
|
190 (*** Towards proving the liveness property ***) |
|
191 |
|
192 lemma client_prog_stable_rel_le_giv: |
|
193 "client_prog \<in> stable({s \<in> state. <s`rel, s`giv> \<in> prefix(nat)})" |
|
194 by (constrains, auto) |
|
195 |
|
196 lemma client_prog_Join_Stable_rel_le_giv: |
|
197 "[| client_prog Join G \<in> Incr(lift(giv)); G \<in> preserves(lift(rel)) |] |
|
198 ==> client_prog Join G \<in> Stable({s \<in> state. <s`rel, s`giv> \<in> prefix(nat)})" |
|
199 apply (rule client_prog_stable_rel_le_giv [THEN Increasing_preserves_Stable]) |
|
200 apply (auto simp add: lift_def) |
|
201 done |
|
202 |
|
203 lemma client_prog_Join_Always_rel_le_giv: |
|
204 "[| client_prog Join G \<in> Incr(lift(giv)); G \<in> preserves(lift(rel)) |] |
|
205 ==> client_prog Join G \<in> Always({s \<in> state. <s`rel, s`giv> \<in> prefix(nat)})" |
|
206 by (force intro!: AlwaysI client_prog_Join_Stable_rel_le_giv) |
|
207 |
|
208 lemma def_act_eq: |
|
209 "A == {<s, t> \<in> state*state. P(s, t)} ==> A={<s, t> \<in> state*state. P(s, t)}" |
|
210 by auto |
|
211 |
|
212 lemma act_subset: "A={<s,t> \<in> state*state. P(s, t)} ==> A<=state*state" |
|
213 by auto |
|
214 |
|
215 lemma transient_lemma: |
|
216 "client_prog \<in> |
|
217 transient({s \<in> state. s`rel = k & <k, h> \<in> strict_prefix(nat) |
|
218 & <h, s`giv> \<in> prefix(nat) & h pfixGe s`ask})" |
|
219 apply (rule_tac act = client_rel_act in transientI) |
|
220 apply (simp (no_asm) add: client_prog_def [THEN def_prg_Acts]) |
|
221 apply (simp (no_asm) add: client_rel_act_def [THEN def_act_eq, THEN act_subset]) |
|
222 apply (auto simp add: client_prog_def [THEN def_prg_Acts] domain_def) |
|
223 apply (rule ReplaceI) |
|
224 apply (rule_tac x = "x (rel:= x`rel @ [nth (length (x`rel), x`giv) ]) " in exI) |
|
225 apply (auto intro!: state_update_type app_type length_type nth_type, auto) |
|
226 apply (blast intro: lt_trans2 prefix_length_le strict_prefix_length_lt) |
|
227 apply (blast intro: lt_trans2 prefix_length_le strict_prefix_length_lt) |
|
228 apply (simp (no_asm_use) add: gen_prefix_iff_nth) |
|
229 apply (subgoal_tac "h \<in> list(nat)") |
|
230 apply (simp_all (no_asm_simp) add: prefix_type [THEN subsetD, THEN SigmaD1]) |
|
231 apply (auto simp add: prefix_def Ge_def) |
|
232 apply (drule strict_prefix_length_lt) |
|
233 apply (drule_tac x = "length (x`rel) " in spec) |
|
234 apply auto |
|
235 apply (simp (no_asm_use) add: gen_prefix_iff_nth) |
|
236 apply (auto simp add: id_def lam_def) |
|
237 done |
|
238 |
|
239 lemma strict_prefix_is_prefix: |
|
240 "<xs, ys> \<in> strict_prefix(A) <-> <xs, ys> \<in> prefix(A) & xs\<noteq>ys" |
|
241 apply (unfold strict_prefix_def id_def lam_def) |
|
242 apply (auto dest: prefix_type [THEN subsetD]) |
|
243 done |
|
244 |
|
245 lemma induct_lemma: |
|
246 "[| client_prog Join G \<in> Incr(lift(giv)); client_prog ok G; G \<in> program |] |
|
247 ==> client_prog Join G \<in> |
|
248 {s \<in> state. s`rel = k & <k,h> \<in> strict_prefix(nat) |
|
249 & <h, s`giv> \<in> prefix(nat) & h pfixGe s`ask} |
|
250 LeadsTo {s \<in> state. <k, s`rel> \<in> strict_prefix(nat) |
|
251 & <s`rel, s`giv> \<in> prefix(nat) & |
|
252 <h, s`giv> \<in> prefix(nat) & |
|
253 h pfixGe s`ask}" |
|
254 apply (rule single_LeadsTo_I) |
|
255 prefer 2 apply simp |
|
256 apply (frule client_prog_Increasing_ask_rel [THEN guaranteesD]) |
|
257 apply (rotate_tac [3] 2) |
|
258 apply (auto simp add: client_prog_ok_iff) |
|
259 apply (rule transient_lemma [THEN Join_transient_I1, THEN transient_imp_leadsTo, THEN leadsTo_imp_LeadsTo, THEN PSP_Stable, THEN LeadsTo_weaken]) |
|
260 apply (rule Stable_Int [THEN Stable_Int, THEN Stable_Int]) |
|
261 apply (erule_tac f = "lift (giv) " and a = "s`giv" in Increasing_imp_Stable) |
|
262 apply (simp (no_asm_simp)) |
|
263 apply (erule_tac f = "lift (ask) " and a = "s`ask" in Increasing_imp_Stable) |
|
264 apply (simp (no_asm_simp)) |
|
265 apply (erule_tac f = "lift (rel) " and a = "s`rel" in Increasing_imp_Stable) |
|
266 apply (simp (no_asm_simp)) |
|
267 apply (erule client_prog_Join_Stable_rel_le_giv, blast, simp_all) |
|
268 prefer 2 |
|
269 apply (blast intro: sym strict_prefix_is_prefix [THEN iffD2] prefix_trans prefix_imp_pfixGe pfixGe_trans) |
|
270 apply (auto intro: strict_prefix_is_prefix [THEN iffD1, THEN conjunct1] |
|
271 prefix_trans) |
|
272 done |
|
273 |
|
274 lemma rel_progress_lemma: |
|
275 "[| client_prog Join G \<in> Incr(lift(giv)); client_prog ok G; G \<in> program |] |
|
276 ==> client_prog Join G \<in> |
|
277 {s \<in> state. <s`rel, h> \<in> strict_prefix(nat) |
|
278 & <h, s`giv> \<in> prefix(nat) & h pfixGe s`ask} |
|
279 LeadsTo {s \<in> state. <h, s`rel> \<in> prefix(nat)}" |
|
280 apply (rule_tac f = "\<lambda>x \<in> state. length(h) #- length(x`rel)" |
|
281 in LessThan_induct) |
|
282 apply (auto simp add: vimage_def) |
|
283 prefer 2 apply (force simp add: lam_def) |
|
284 apply (rule single_LeadsTo_I) |
|
285 prefer 2 apply simp |
|
286 apply (subgoal_tac "h \<in> list(nat)") |
|
287 prefer 2 apply (blast dest: prefix_type [THEN subsetD]) |
|
288 apply (rule induct_lemma [THEN LeadsTo_weaken]) |
|
289 apply (simp add: length_type lam_def) |
|
290 apply (auto intro: strict_prefix_is_prefix [THEN iffD2] |
|
291 dest: common_prefix_linear prefix_type [THEN subsetD]) |
|
292 apply (erule swap) |
|
293 apply (rule imageI) |
|
294 apply (force dest!: simp add: lam_def) |
|
295 apply (simp add: length_type lam_def, clarify) |
|
296 apply (drule strict_prefix_length_lt)+ |
|
297 apply (drule less_imp_succ_add, simp)+ |
|
298 apply clarify |
|
299 apply simp |
|
300 apply (erule diff_le_self [THEN ltD]) |
|
301 done |
|
302 |
|
303 lemma progress_lemma: |
|
304 "[| client_prog Join G \<in> Incr(lift(giv)); client_prog ok G; G \<in> program |] |
|
305 ==> client_prog Join G \<in> |
|
306 {s \<in> state. <h, s`giv> \<in> prefix(nat) & h pfixGe s`ask} |
|
307 LeadsTo {s \<in> state. <h, s`rel> \<in> prefix(nat)}" |
|
308 apply (rule client_prog_Join_Always_rel_le_giv [THEN Always_LeadsToI], assumption) |
|
309 apply (force simp add: client_prog_ok_iff) |
|
310 apply (rule LeadsTo_weaken_L) |
|
311 apply (rule LeadsTo_Un [OF rel_progress_lemma |
|
312 subset_refl [THEN subset_imp_LeadsTo]]) |
|
313 apply (auto intro: strict_prefix_is_prefix [THEN iffD2] |
|
314 dest: common_prefix_linear prefix_type [THEN subsetD]) |
|
315 done |
|
316 |
|
317 (*Progress property: all tokens that are given will be released*) |
|
318 lemma client_prog_progress: |
|
319 "client_prog \<in> Incr(lift(giv)) guarantees |
|
320 (\<Inter>h \<in> list(nat). {s \<in> state. <h, s`giv> \<in> prefix(nat) & |
|
321 h pfixGe s`ask} LeadsTo {s \<in> state. <h, s`rel> \<in> prefix(nat)})" |
|
322 apply (rule guaranteesI) |
|
323 apply (blast intro: progress_lemma, auto) |
|
324 done |
|
325 |
|
326 lemma client_prog_Allowed: |
|
327 "Allowed(client_prog) = |
|
328 preserves(lift(rel)) Int preserves(lift(ask)) Int preserves(lift(tok))" |
|
329 apply (cut_tac v = "lift (ask)" in preserves_type) |
|
330 apply (auto simp add: Allowed_def client_prog_def [THEN def_prg_Allowed] |
|
331 cons_Int_distrib safety_prop_Acts_iff) |
|
332 done |
|
333 |
64 end |
334 end |