150 thus ?thesis by simp |
154 thus ?thesis by simp |
151 qed |
155 qed |
152 thus ?thesis by (unfold cp_eq_cpreced cpreced_def, fold the_preced_def, simp) |
156 thus ?thesis by (unfold cp_eq_cpreced cpreced_def, fold the_preced_def, simp) |
153 qed |
157 qed |
154 |
158 |
|
159 lemma RAG_target_th: "(Th th, x) \<in> RAG (s::state) \<Longrightarrow> \<exists> cs. x = Cs cs" |
|
160 by (unfold s_RAG_def, auto) |
|
161 |
|
162 lemma waiting_eq: "waiting s th cs = waiting (wq s) th cs" |
|
163 by (unfold s_waiting_def cs_waiting_def wq_def, auto) |
|
164 |
|
165 lemma holding_eq: "holding (s::state) th cs = holding (wq s) th cs" |
|
166 by (unfold s_holding_def wq_def cs_holding_def, simp) |
|
167 |
|
168 lemma runing_ready: |
|
169 shows "runing s \<subseteq> readys s" |
|
170 unfolding runing_def readys_def |
|
171 by auto |
|
172 |
|
173 lemma readys_threads: |
|
174 shows "readys s \<subseteq> threads s" |
|
175 unfolding readys_def |
|
176 by auto |
|
177 |
|
178 lemma wq_v_neq [simp]: |
|
179 "cs \<noteq> cs' \<Longrightarrow> wq (V thread cs#s) cs' = wq s cs'" |
|
180 by (auto simp:wq_def Let_def cp_def split:list.splits) |
|
181 |
|
182 lemma runing_head: |
|
183 assumes "th \<in> runing s" |
|
184 and "th \<in> set (wq_fun (schs s) cs)" |
|
185 shows "th = hd (wq_fun (schs s) cs)" |
|
186 using assms |
|
187 by (simp add:runing_def readys_def s_waiting_def wq_def) |
|
188 |
|
189 lemma runing_wqE: |
|
190 assumes "th \<in> runing s" |
|
191 and "th \<in> set (wq s cs)" |
|
192 obtains rest where "wq s cs = th#rest" |
|
193 proof - |
|
194 from assms(2) obtain th' rest where eq_wq: "wq s cs = th'#rest" |
|
195 by (meson list.set_cases) |
|
196 have "th' = th" |
|
197 proof(rule ccontr) |
|
198 assume "th' \<noteq> th" |
|
199 hence "th \<noteq> hd (wq s cs)" using eq_wq by auto |
|
200 with assms(2) |
|
201 have "waiting s th cs" |
|
202 by (unfold s_waiting_def, fold wq_def, auto) |
|
203 with assms show False |
|
204 by (unfold runing_def readys_def, auto) |
|
205 qed |
|
206 with eq_wq that show ?thesis by metis |
|
207 qed |
|
208 |
155 (* ccc *) |
209 (* ccc *) |
156 |
210 |
157 |
211 section {* Locales used to investigate the execution of PIP *} |
|
212 |
|
213 text {* |
|
214 The following locale @{text valid_trace} is used to constrain the |
|
215 trace to be valid. All properties hold for valid traces are |
|
216 derived under this locale. |
|
217 *} |
158 locale valid_trace = |
218 locale valid_trace = |
159 fixes s |
219 fixes s |
160 assumes vt : "vt s" |
220 assumes vt : "vt s" |
|
221 |
|
222 text {* |
|
223 The following locale @{text valid_trace_e} describes |
|
224 the valid extension of a valid trace. The event @{text "e"} |
|
225 represents an event in the system, which corresponds |
|
226 to a one step operation of the PIP protocol. |
|
227 It is required that @{text "e"} is an event eligible to happen |
|
228 under state @{text "s"}, which is already required to be valid |
|
229 by the parent locale @{text "valid_trace"}. |
|
230 |
|
231 This locale is used to investigate one step execution of PIP, |
|
232 properties concerning the effects of @{text "e"}'s execution, |
|
233 for example, how the values of observation functions are changed, |
|
234 or how desirable properties are kept invariant, are derived |
|
235 under this locale. The state before execution is @{text "s"}, while |
|
236 the state after execution is @{text "e#s"}. Therefore, the lemmas |
|
237 derived usually relate observations on @{text "e#s"} to those |
|
238 on @{text "s"}. |
|
239 *} |
161 |
240 |
162 locale valid_trace_e = valid_trace + |
241 locale valid_trace_e = valid_trace + |
163 fixes e |
242 fixes e |
164 assumes vt_e: "vt (e#s)" |
243 assumes vt_e: "vt (e#s)" |
165 begin |
244 begin |
166 |
245 |
|
246 text {* |
|
247 The following lemma shows that @{text "e"} must be a |
|
248 eligible event (or a valid step) to be taken under |
|
249 the state represented by @{text "s"}. |
|
250 *} |
167 lemma pip_e: "PIP s e" |
251 lemma pip_e: "PIP s e" |
168 using vt_e by (cases, simp) |
252 using vt_e by (cases, simp) |
169 |
253 |
170 end |
254 end |
171 |
255 |
|
256 text {* |
|
257 Because @{term "e#s"} is also a valid trace, properties |
|
258 derived for valid trace @{term s} also hold on @{term "e#s"}. |
|
259 *} |
|
260 sublocale valid_trace_e < vat_es!: valid_trace "e#s" |
|
261 using vt_e |
|
262 by (unfold_locales, simp) |
|
263 |
|
264 text {* |
|
265 For each specific event (or operation), there is a sublocale |
|
266 further constraining that the event @{text e} to be that |
|
267 particular event. |
|
268 |
|
269 For example, the following |
|
270 locale @{text "valid_trace_create"} is the sublocale for |
|
271 event @{term "Create"}: |
|
272 *} |
172 locale valid_trace_create = valid_trace_e + |
273 locale valid_trace_create = valid_trace_e + |
173 fixes th prio |
274 fixes th prio |
174 assumes is_create: "e = Create th prio" |
275 assumes is_create: "e = Create th prio" |
175 |
276 |
176 locale valid_trace_exit = valid_trace_e + |
277 locale valid_trace_exit = valid_trace_e + |
179 |
280 |
180 locale valid_trace_p = valid_trace_e + |
281 locale valid_trace_p = valid_trace_e + |
181 fixes th cs |
282 fixes th cs |
182 assumes is_p: "e = P th cs" |
283 assumes is_p: "e = P th cs" |
183 |
284 |
|
285 text {* |
|
286 locale @{text "valid_trace_p"} is divided further into two |
|
287 sublocales, namely, @{text "valid_trace_p_h"} |
|
288 and @{text "valid_trace_p_w"}. |
|
289 *} |
|
290 |
|
291 text {* |
|
292 The following two sublocales @{text "valid_trace_p_h"} |
|
293 and @{text "valid_trace_p_w"} represent two complementary |
|
294 cases under @{text "valid_trace_p"}, where |
|
295 @{text "valid_trace_p_h"} further constraints that |
|
296 @{text "wq s cs = []"}, which means the waiting queue of |
|
297 the requested resource @{text "cs"} is empty, in which |
|
298 case, the requesting thread @{text "th"} |
|
299 will take hold of @{text "cs"}. |
|
300 |
|
301 Opposite to @{text "valid_trace_p_h"}, |
|
302 @{text "valid_trace_p_w"} constraints that |
|
303 @{text "wq s cs \<noteq> []"}, which means the waiting queue of |
|
304 the requested resource @{text "cs"} is nonempty, in which |
|
305 case, the requesting thread @{text "th"} will be blocked |
|
306 on @{text "cs"}: |
|
307 |
|
308 Peculiar properties will be derived under respective |
|
309 locales. |
|
310 *} |
|
311 |
|
312 locale valid_trace_p_h = valid_trace_p + |
|
313 assumes we: "wq s cs = []" |
|
314 |
|
315 locale valid_trace_p_w = valid_trace_p + |
|
316 assumes wne: "wq s cs \<noteq> []" |
|
317 begin |
|
318 |
|
319 text {* |
|
320 The following @{text "holder"} designates |
|
321 the holder of @{text "cs"} before the @{text "P"}-operation. |
|
322 *} |
|
323 definition "holder = hd (wq s cs)" |
|
324 |
|
325 text {* |
|
326 The following @{text "waiters"} designates |
|
327 the list of threads waiting for @{text "cs"} |
|
328 before the @{text "P"}-operation. |
|
329 *} |
|
330 definition "waiters = tl (wq s cs)" |
|
331 end |
|
332 |
|
333 text {* |
|
334 @{text "valid_trace_v"} is set for the @{term V}-operation. |
|
335 *} |
184 locale valid_trace_v = valid_trace_e + |
336 locale valid_trace_v = valid_trace_e + |
185 fixes th cs |
337 fixes th cs |
186 assumes is_v: "e = V th cs" |
338 assumes is_v: "e = V th cs" |
187 begin |
339 begin |
|
340 -- {* The following @{text "rest"} is the tail of |
|
341 waiting queue of the resource @{text "cs"} |
|
342 to be released by this @{text "V"}-operation. |
|
343 *} |
188 definition "rest = tl (wq s cs)" |
344 definition "rest = tl (wq s cs)" |
|
345 |
|
346 text {* |
|
347 The following @{text "wq'"} is the waiting |
|
348 queue of @{term "cs"} |
|
349 after the @{text "V"}-operation, which |
|
350 is simply a reordering of @{term "rest"}. |
|
351 |
|
352 The effect of this reordering needs to be |
|
353 understood by two cases: |
|
354 \begin{enumerate} |
|
355 \item When @{text "rest = []"}, |
|
356 the reordering gives rise to an empty list as well, |
|
357 which means there is no thread holding or waiting |
|
358 for resource @{term "cs"}, therefore, it is free. |
|
359 |
|
360 \item When @{text "rest \<noteq> []"}, the effect of |
|
361 this reordering is to arbitrarily |
|
362 switch one thread in @{term "rest"} to the |
|
363 head, which, by definition take over the hold |
|
364 of @{term "cs"} and is designated by @{text "taker"} |
|
365 in the following sublocale @{text "valid_trace_v_n"}. |
|
366 *} |
189 definition "wq' = (SOME q. distinct q \<and> set q = set rest)" |
367 definition "wq' = (SOME q. distinct q \<and> set q = set rest)" |
|
368 |
|
369 text {* |
|
370 The following @{text "rest'"} is the tail of the |
|
371 waiting queue after the @{text "V"}-operation. |
|
372 It plays only auxiliary role to ease reasoning. |
|
373 *} |
|
374 definition "rest' = tl wq'" |
|
375 |
190 end |
376 end |
|
377 |
|
378 text {* |
|
379 In the following, @{text "valid_trace_v"} is also |
|
380 divided into two |
|
381 sublocales: when @{text "rest"} is empty (represented |
|
382 by @{text "valid_trace_v_e"}), which means, there is no thread waiting |
|
383 for @{text "cs"}, therefore, after the @{text "V"}-operation, |
|
384 it will become free; otherwise (represented |
|
385 by @{text "valid_trace_v_n"}), one thread |
|
386 will be picked from those in @{text "rest"} to take |
|
387 over @{text "cs"}. |
|
388 *} |
|
389 |
|
390 locale valid_trace_v_e = valid_trace_v + |
|
391 assumes rest_nil: "rest = []" |
191 |
392 |
192 locale valid_trace_v_n = valid_trace_v + |
393 locale valid_trace_v_n = valid_trace_v + |
193 assumes rest_nnl: "rest \<noteq> []" |
394 assumes rest_nnl: "rest \<noteq> []" |
194 |
395 begin |
195 locale valid_trace_v_e = valid_trace_v + |
396 |
196 assumes rest_nil: "rest = []" |
397 text {* |
197 |
398 The following @{text "taker"} is the thread to |
198 locale valid_trace_set= valid_trace_e + |
399 take over @{text "cs"}. |
|
400 *} |
|
401 definition "taker = hd wq'" |
|
402 |
|
403 end |
|
404 |
|
405 |
|
406 locale valid_trace_set = valid_trace_e + |
199 fixes th prio |
407 fixes th prio |
200 assumes is_set: "e = Set th prio" |
408 assumes is_set: "e = Set th prio" |
201 |
409 |
202 context valid_trace |
410 context valid_trace |
203 begin |
411 begin |
204 |
412 |
|
413 text {* |
|
414 Induction rule introduced to easy the |
|
415 derivation of properties for valid trace @{term "s"}. |
|
416 One more premises, namely @{term "valid_trace_e s e"} |
|
417 is added, so that an interpretation of |
|
418 @{text "valid_trace_e"} can be instantiated |
|
419 so that all properties derived so far becomes |
|
420 available in the proof of induction step. |
|
421 |
|
422 You will see its use in the proofs that follows. |
|
423 *} |
205 lemma ind [consumes 0, case_names Nil Cons, induct type]: |
424 lemma ind [consumes 0, case_names Nil Cons, induct type]: |
206 assumes "PP []" |
425 assumes "PP []" |
207 and "(\<And>s e. valid_trace_e s e \<Longrightarrow> |
426 and "(\<And>s e. valid_trace_e s e \<Longrightarrow> |
208 PP s \<Longrightarrow> PIP s e \<Longrightarrow> PP (e # s))" |
427 PP s \<Longrightarrow> PIP s e \<Longrightarrow> PP (e # s))" |
209 shows "PP s" |
428 shows "PP s" |
244 show ?thesis by simp |
468 show ?thesis by simp |
245 qed |
469 qed |
246 ultimately show ?thesis by simp |
470 ultimately show ?thesis by simp |
247 qed |
471 qed |
248 qed |
472 qed |
249 |
|
250 lemma finite_threads: |
|
251 shows "finite (threads s)" |
|
252 using vt by (induct) (auto elim: step.cases) |
|
253 |
|
254 end |
473 end |
255 |
474 |
256 lemma RAG_target_th: "(Th th, x) \<in> RAG (s::state) \<Longrightarrow> \<exists> cs. x = Cs cs" |
475 text {* |
257 by (unfold s_RAG_def, auto) |
476 The following locale @{text "valid_moment"} is to inherit the properties |
258 |
477 derived on any valid state to the prefix of it, with length @{text "i"}. |
|
478 *} |
259 locale valid_moment = valid_trace + |
479 locale valid_moment = valid_trace + |
260 fixes i :: nat |
480 fixes i :: nat |
261 |
481 |
262 sublocale valid_moment < vat_moment: valid_trace "(moment i s)" |
482 sublocale valid_moment < vat_moment: valid_trace "(moment i s)" |
263 by (unfold_locales, insert vt_moment, auto) |
483 by (unfold_locales, insert vt_moment, auto) |
264 |
484 |
265 lemma waiting_eq: "waiting s th cs = waiting (wq s) th cs" |
|
266 by (unfold s_waiting_def cs_waiting_def wq_def, auto) |
|
267 |
|
268 lemma holding_eq: "holding (s::state) th cs = holding (wq s) th cs" |
|
269 by (unfold s_holding_def wq_def cs_holding_def, simp) |
|
270 |
|
271 lemma runing_ready: |
|
272 shows "runing s \<subseteq> readys s" |
|
273 unfolding runing_def readys_def |
|
274 by auto |
|
275 |
|
276 lemma readys_threads: |
|
277 shows "readys s \<subseteq> threads s" |
|
278 unfolding readys_def |
|
279 by auto |
|
280 |
|
281 lemma wq_v_neq [simp]: |
|
282 "cs \<noteq> cs' \<Longrightarrow> wq (V thread cs#s) cs' = wq s cs'" |
|
283 by (auto simp:wq_def Let_def cp_def split:list.splits) |
|
284 |
|
285 lemma runing_head: |
|
286 assumes "th \<in> runing s" |
|
287 and "th \<in> set (wq_fun (schs s) cs)" |
|
288 shows "th = hd (wq_fun (schs s) cs)" |
|
289 using assms |
|
290 by (simp add:runing_def readys_def s_waiting_def wq_def) |
|
291 |
|
292 context valid_trace |
|
293 begin |
|
294 |
|
295 lemma runing_wqE: |
|
296 assumes "th \<in> runing s" |
|
297 and "th \<in> set (wq s cs)" |
|
298 obtains rest where "wq s cs = th#rest" |
|
299 proof - |
|
300 from assms(2) obtain th' rest where eq_wq: "wq s cs = th'#rest" |
|
301 by (meson list.set_cases) |
|
302 have "th' = th" |
|
303 proof(rule ccontr) |
|
304 assume "th' \<noteq> th" |
|
305 hence "th \<noteq> hd (wq s cs)" using eq_wq by auto |
|
306 with assms(2) |
|
307 have "waiting s th cs" |
|
308 by (unfold s_waiting_def, fold wq_def, auto) |
|
309 with assms show False |
|
310 by (unfold runing_def readys_def, auto) |
|
311 qed |
|
312 with eq_wq that show ?thesis by metis |
|
313 qed |
|
314 |
|
315 end |
|
316 |
485 |
317 context valid_trace_create |
486 context valid_trace_create |
318 begin |
487 begin |
319 |
488 |
320 lemma wq_neq_simp [simp]: |
489 lemma wq_kept [simp]: |
321 shows "wq (e#s) cs' = wq s cs'" |
490 shows "wq (e#s) cs' = wq s cs'" |
322 using assms unfolding is_create wq_def |
491 using assms unfolding is_create wq_def |
323 by (auto simp:Let_def) |
492 by (auto simp:Let_def) |
324 |
493 |
325 lemma wq_distinct_kept: |
494 lemma wq_distinct_kept: |
3210 by (unfold is_create, simp) |
3373 by (unfold is_create, simp) |
3211 |
3374 |
3212 lemma not_waiting_th_s [simp]: "\<not> waiting s th cs'" |
3375 lemma not_waiting_th_s [simp]: "\<not> waiting s th cs'" |
3213 proof |
3376 proof |
3214 assume "waiting s th cs'" |
3377 assume "waiting s th cs'" |
3215 from this[unfolded s_waiting_def, folded wq_def, unfolded wq_neq_simp] |
3378 from this[unfolded s_waiting_def, folded wq_def, unfolded wq_kept] |
3216 have "th \<in> set (wq s cs')" by auto |
3379 have "th \<in> set (wq s cs')" by auto |
3217 from wq_threads[OF this] have "th \<in> threads s" . |
3380 from wq_threads[OF this] have "th \<in> threads s" . |
3218 with th_not_live_s show False by simp |
3381 with th_not_live_s show False by simp |
3219 qed |
3382 qed |
3220 |
3383 |
3221 lemma not_holding_th_s [simp]: "\<not> holding s th cs'" |
3384 lemma not_holding_th_s [simp]: "\<not> holding s th cs'" |
3222 proof |
3385 proof |
3223 assume "holding s th cs'" |
3386 assume "holding s th cs'" |
3224 from this[unfolded s_holding_def, folded wq_def, unfolded wq_neq_simp] |
3387 from this[unfolded s_holding_def, folded wq_def, unfolded wq_kept] |
3225 have "th \<in> set (wq s cs')" by auto |
3388 have "th \<in> set (wq s cs')" by auto |
3226 from wq_threads[OF this] have "th \<in> threads s" . |
3389 from wq_threads[OF this] have "th \<in> threads s" . |
3227 with th_not_live_s show False by simp |
3390 with th_not_live_s show False by simp |
3228 qed |
3391 qed |
3229 |
3392 |
3230 lemma not_waiting_th_es [simp]: "\<not> waiting (e#s) th cs'" |
3393 lemma not_waiting_th_es [simp]: "\<not> waiting (e#s) th cs'" |
3231 proof |
3394 proof |
3232 assume "waiting (e # s) th cs'" |
3395 assume "waiting (e # s) th cs'" |
3233 from this[unfolded s_waiting_def, folded wq_def, unfolded wq_neq_simp] |
3396 from this[unfolded s_waiting_def, folded wq_def, unfolded wq_kept] |
3234 have "th \<in> set (wq s cs')" by auto |
3397 have "th \<in> set (wq s cs')" by auto |
3235 from wq_threads[OF this] have "th \<in> threads s" . |
3398 from wq_threads[OF this] have "th \<in> threads s" . |
3236 with th_not_live_s show False by simp |
3399 with th_not_live_s show False by simp |
3237 qed |
3400 qed |
3238 |
3401 |
3239 lemma not_holding_th_es [simp]: "\<not> holding (e#s) th cs'" |
3402 lemma not_holding_th_es [simp]: "\<not> holding (e#s) th cs'" |
3240 proof |
3403 proof |
3241 assume "holding (e # s) th cs'" |
3404 assume "holding (e # s) th cs'" |
3242 from this[unfolded s_holding_def, folded wq_def, unfolded wq_neq_simp] |
3405 from this[unfolded s_holding_def, folded wq_def, unfolded wq_kept] |
3243 have "th \<in> set (wq s cs')" by auto |
3406 have "th \<in> set (wq s cs')" by auto |
3244 from wq_threads[OF this] have "th \<in> threads s" . |
3407 from wq_threads[OF this] have "th \<in> threads s" . |
3245 with th_not_live_s show False by simp |
3408 with th_not_live_s show False by simp |
3246 qed |
3409 qed |
3247 |
3410 |
3272 proof - |
3435 proof - |
3273 { fix cs' |
3436 { fix cs' |
3274 assume h: "cs' \<in> ?L" |
3437 assume h: "cs' \<in> ?L" |
3275 hence "cs' \<in> ?R" |
3438 hence "cs' \<in> ?R" |
3276 by (unfold holdents_def s_holding_def, fold wq_def, |
3439 by (unfold holdents_def s_holding_def, fold wq_def, |
3277 unfold wq_neq_simp, auto) |
3440 unfold wq_kept, auto) |
3278 } moreover { |
3441 } moreover { |
3279 fix cs' |
3442 fix cs' |
3280 assume h: "cs' \<in> ?R" |
3443 assume h: "cs' \<in> ?R" |
3281 hence "cs' \<in> ?L" |
3444 hence "cs' \<in> ?L" |
3282 by (unfold holdents_def s_holding_def, fold wq_def, |
3445 by (unfold holdents_def s_holding_def, fold wq_def, |
3283 unfold wq_neq_simp, auto) |
3446 unfold wq_kept, auto) |
3284 } ultimately show ?thesis by auto |
3447 } ultimately show ?thesis by auto |
3285 qed |
3448 qed |
3286 |
3449 |
3287 lemma cntCS_kept [simp]: |
3450 lemma cntCS_kept [simp]: |
3288 assumes "th' \<noteq> th" |
3451 assumes "th' \<noteq> th" |
3419 proof - |
3582 proof - |
3420 { fix cs' |
3583 { fix cs' |
3421 assume h: "cs' \<in> ?L" |
3584 assume h: "cs' \<in> ?L" |
3422 hence "cs' \<in> ?R" |
3585 hence "cs' \<in> ?R" |
3423 by (unfold holdents_def s_holding_def, fold wq_def, |
3586 by (unfold holdents_def s_holding_def, fold wq_def, |
3424 unfold wq_neq_simp, auto) |
3587 unfold wq_kept, auto) |
3425 } moreover { |
3588 } moreover { |
3426 fix cs' |
3589 fix cs' |
3427 assume h: "cs' \<in> ?R" |
3590 assume h: "cs' \<in> ?R" |
3428 hence "cs' \<in> ?L" |
3591 hence "cs' \<in> ?L" |
3429 by (unfold holdents_def s_holding_def, fold wq_def, |
3592 by (unfold holdents_def s_holding_def, fold wq_def, |
3430 unfold wq_neq_simp, auto) |
3593 unfold wq_kept, auto) |
3431 } ultimately show ?thesis by auto |
3594 } ultimately show ?thesis by auto |
3432 qed |
3595 qed |
3433 |
3596 |
3434 lemma cntCS_kept [simp]: |
3597 lemma cntCS_kept [simp]: |
3435 assumes "th' \<noteq> th" |
3598 assumes "th' \<noteq> th" |
3524 proof - |
3687 proof - |
3525 { fix cs' |
3688 { fix cs' |
3526 assume h: "cs' \<in> ?L" |
3689 assume h: "cs' \<in> ?L" |
3527 hence "cs' \<in> ?R" |
3690 hence "cs' \<in> ?R" |
3528 by (unfold holdents_def s_holding_def, fold wq_def, |
3691 by (unfold holdents_def s_holding_def, fold wq_def, |
3529 unfold wq_neq_simp, auto) |
3692 unfold wq_kept, auto) |
3530 } moreover { |
3693 } moreover { |
3531 fix cs' |
3694 fix cs' |
3532 assume h: "cs' \<in> ?R" |
3695 assume h: "cs' \<in> ?R" |
3533 hence "cs' \<in> ?L" |
3696 hence "cs' \<in> ?L" |
3534 by (unfold holdents_def s_holding_def, fold wq_def, |
3697 by (unfold holdents_def s_holding_def, fold wq_def, |
3535 unfold wq_neq_simp, auto) |
3698 unfold wq_kept, auto) |
3536 } ultimately show ?thesis by auto |
3699 } ultimately show ?thesis by auto |
3537 qed |
3700 qed |
3538 |
3701 |
3539 lemma cntCS_kept [simp]: |
3702 lemma cntCS_kept [simp]: |
3540 shows "cntCS (e#s) th' = cntCS s th'" (is "?L = ?R") |
3703 shows "cntCS (e#s) th' = cntCS s th'" (is "?L = ?R") |