author | wenzelm |
Sat, 03 Sep 2022 15:39:26 +0200 | |
changeset 76044 | c90799513ed0 |
parent 69587 | 53982d5ec0bb |
child 76213 | e44d86131648 |
permissions | -rw-r--r-- |
37936 | 1 |
(* Title: ZF/UNITY/WFair.thy |
11479 | 2 |
Author: Sidi Ehmety, Computer Laboratory |
3 |
Copyright 1998 University of Cambridge |
|
4 |
*) |
|
5 |
||
60770 | 6 |
section\<open>Progress under Weak Fairness\<close> |
15634 | 7 |
|
8 |
theory WFair |
|
65449
c82e63b11b8b
clarified main ZF.thy / ZFC.thy, and avoid name clash with global HOL/Main.thy;
wenzelm
parents:
61798
diff
changeset
|
9 |
imports UNITY ZFC |
15634 | 10 |
begin |
11 |
||
60770 | 12 |
text\<open>This theory defines the operators transient, ensures and leadsTo, |
15634 | 13 |
assuming weak fairness. From Misra, "A Logic for Concurrent Programming", |
60770 | 14 |
1994.\<close> |
15634 | 15 |
|
24893 | 16 |
definition |
12195 | 17 |
(* This definition specifies weak fairness. The rest of the theory |
46953 | 18 |
is generic to all forms of fairness.*) |
24893 | 19 |
transient :: "i=>i" where |
46953 | 20 |
"transient(A) =={F \<in> program. (\<exists>act\<in>Acts(F). A<=domain(act) & |
46823 | 21 |
act``A \<subseteq> state-A) & st_set(A)}" |
11479 | 22 |
|
24893 | 23 |
definition |
69587 | 24 |
ensures :: "[i,i] => i" (infixl \<open>ensures\<close> 60) where |
46823 | 25 |
"A ensures B == ((A-B) co (A \<union> B)) \<inter> transient(A-B)" |
46953 | 26 |
|
11479 | 27 |
consts |
28 |
||
29 |
(*LEADS-TO constant for the inductive definition*) |
|
12195 | 30 |
leads :: "[i, i]=>i" |
11479 | 31 |
|
46953 | 32 |
inductive |
11479 | 33 |
domains |
46823 | 34 |
"leads(D, F)" \<subseteq> "Pow(D)*Pow(D)" |
46953 | 35 |
intros |
36 |
Basis: "[| F \<in> A ensures B; A \<in> Pow(D); B \<in> Pow(D) |] ==> <A,B>:leads(D, F)" |
|
46823 | 37 |
Trans: "[| <A,B> \<in> leads(D, F); <B,C> \<in> leads(D, F) |] ==> <A,C>:leads(D, F)" |
46953 | 38 |
Union: "[| S \<in> Pow({A \<in> S. <A, B>:leads(D, F)}); B \<in> Pow(D); S \<in> Pow(Pow(D)) |] ==> |
46823 | 39 |
<\<Union>(S),B>:leads(D, F)" |
11479 | 40 |
|
41 |
monos Pow_mono |
|
15634 | 42 |
type_intros Union_Pow_iff [THEN iffD2] UnionI PowI |
46953 | 43 |
|
24893 | 44 |
definition |
12195 | 45 |
(* The Visible version of the LEADS-TO relation*) |
69587 | 46 |
leadsTo :: "[i, i] => i" (infixl \<open>\<longmapsto>\<close> 60) where |
61392 | 47 |
"A \<longmapsto> B == {F \<in> program. <A,B>:leads(state, F)}" |
46953 | 48 |
|
24893 | 49 |
definition |
12195 | 50 |
(* wlt(F, B) is the largest set that leads to B*) |
24893 | 51 |
wlt :: "[i, i] => i" where |
61392 | 52 |
"wlt(F, B) == \<Union>({A \<in> Pow(state). F \<in> A \<longmapsto> B})" |
15634 | 53 |
|
54 |
(** Ad-hoc set-theory rules **) |
|
55 |
||
46823 | 56 |
lemma Int_Union_Union: "\<Union>(B) \<inter> A = (\<Union>b \<in> B. b \<inter> A)" |
15634 | 57 |
by auto |
58 |
||
46823 | 59 |
lemma Int_Union_Union2: "A \<inter> \<Union>(B) = (\<Union>b \<in> B. A \<inter> b)" |
15634 | 60 |
by auto |
61 |
||
62 |
(*** transient ***) |
|
63 |
||
64 |
lemma transient_type: "transient(A)<=program" |
|
65 |
by (unfold transient_def, auto) |
|
66 |
||
46953 | 67 |
lemma transientD2: |
15634 | 68 |
"F \<in> transient(A) ==> F \<in> program & st_set(A)" |
69 |
apply (unfold transient_def, auto) |
|
70 |
done |
|
71 |
||
72 |
lemma stable_transient_empty: "[| F \<in> stable(A); F \<in> transient(A) |] ==> A = 0" |
|
73 |
by (simp add: stable_def constrains_def transient_def, fast) |
|
74 |
||
75 |
lemma transient_strengthen: "[|F \<in> transient(A); B<=A|] ==> F \<in> transient(B)" |
|
76 |
apply (simp add: transient_def st_set_def, clarify) |
|
77 |
apply (blast intro!: rev_bexI) |
|
78 |
done |
|
79 |
||
46953 | 80 |
lemma transientI: |
81 |
"[|act \<in> Acts(F); A \<subseteq> domain(act); act``A \<subseteq> state-A; |
|
15634 | 82 |
F \<in> program; st_set(A)|] ==> F \<in> transient(A)" |
83 |
by (simp add: transient_def, blast) |
|
84 |
||
46953 | 85 |
lemma transientE: |
86 |
"[| F \<in> transient(A); |
|
46823 | 87 |
!!act. [| act \<in> Acts(F); A \<subseteq> domain(act); act``A \<subseteq> state-A|]==>P|] |
15634 | 88 |
==>P" |
89 |
by (simp add: transient_def, blast) |
|
90 |
||
91 |
lemma transient_state: "transient(state) = 0" |
|
92 |
apply (simp add: transient_def) |
|
46953 | 93 |
apply (rule equalityI, auto) |
15634 | 94 |
apply (cut_tac F = x in Acts_type) |
95 |
apply (simp add: Diff_cancel) |
|
96 |
apply (auto intro: st0_in_state) |
|
97 |
done |
|
98 |
||
99 |
lemma transient_state2: "state<=B ==> transient(B) = 0" |
|
100 |
apply (simp add: transient_def st_set_def) |
|
101 |
apply (rule equalityI, auto) |
|
102 |
apply (cut_tac F = x in Acts_type) |
|
103 |
apply (subgoal_tac "B=state") |
|
104 |
apply (auto intro: st0_in_state) |
|
105 |
done |
|
106 |
||
107 |
lemma transient_empty: "transient(0) = program" |
|
108 |
by (auto simp add: transient_def) |
|
109 |
||
110 |
declare transient_empty [simp] transient_state [simp] transient_state2 [simp] |
|
111 |
||
112 |
(*** ensures ***) |
|
113 |
||
114 |
lemma ensures_type: "A ensures B <=program" |
|
115 |
by (simp add: ensures_def constrains_def, auto) |
|
116 |
||
46953 | 117 |
lemma ensuresI: |
46823 | 118 |
"[|F:(A-B) co (A \<union> B); F \<in> transient(A-B)|]==>F \<in> A ensures B" |
15634 | 119 |
apply (unfold ensures_def) |
120 |
apply (auto simp add: transient_type [THEN subsetD]) |
|
121 |
done |
|
122 |
||
123 |
(* Added by Sidi, from Misra's notes, Progress chapter, exercise 4 *) |
|
46823 | 124 |
lemma ensuresI2: "[| F \<in> A co A \<union> B; F \<in> transient(A) |] ==> F \<in> A ensures B" |
15634 | 125 |
apply (drule_tac B = "A-B" in constrains_weaken_L) |
126 |
apply (drule_tac [2] B = "A-B" in transient_strengthen) |
|
127 |
apply (auto simp add: ensures_def transient_type [THEN subsetD]) |
|
128 |
done |
|
129 |
||
46823 | 130 |
lemma ensuresD: "F \<in> A ensures B ==> F:(A-B) co (A \<union> B) & F \<in> transient (A-B)" |
15634 | 131 |
by (unfold ensures_def, auto) |
132 |
||
133 |
lemma ensures_weaken_R: "[|F \<in> A ensures A'; A'<=B' |] ==> F \<in> A ensures B'" |
|
134 |
apply (unfold ensures_def) |
|
135 |
apply (blast intro: transient_strengthen constrains_weaken) |
|
136 |
done |
|
137 |
||
46953 | 138 |
(*The L-version (precondition strengthening) fails, but we have this*) |
139 |
lemma stable_ensures_Int: |
|
46823 | 140 |
"[| F \<in> stable(C); F \<in> A ensures B |] ==> F:(C \<inter> A) ensures (C \<inter> B)" |
46953 | 141 |
|
15634 | 142 |
apply (unfold ensures_def) |
143 |
apply (simp (no_asm) add: Int_Un_distrib [symmetric] Diff_Int_distrib [symmetric]) |
|
144 |
apply (blast intro: transient_strengthen stable_constrains_Int constrains_weaken) |
|
145 |
done |
|
146 |
||
46823 | 147 |
lemma stable_transient_ensures: "[|F \<in> stable(A); F \<in> transient(C); A<=B \<union> C|] ==> F \<in> A ensures B" |
15634 | 148 |
apply (frule stable_type [THEN subsetD]) |
149 |
apply (simp add: ensures_def stable_def) |
|
150 |
apply (blast intro: transient_strengthen constrains_weaken) |
|
151 |
done |
|
152 |
||
46823 | 153 |
lemma ensures_eq: "(A ensures B) = (A unless B) \<inter> transient (A-B)" |
15634 | 154 |
by (auto simp add: ensures_def unless_def) |
155 |
||
156 |
lemma subset_imp_ensures: "[| F \<in> program; A<=B |] ==> F \<in> A ensures B" |
|
157 |
by (auto simp add: ensures_def constrains_def transient_def st_set_def) |
|
158 |
||
159 |
(*** leadsTo ***) |
|
160 |
lemmas leads_left = leads.dom_subset [THEN subsetD, THEN SigmaD1] |
|
161 |
lemmas leads_right = leads.dom_subset [THEN subsetD, THEN SigmaD2] |
|
162 |
||
61392 | 163 |
lemma leadsTo_type: "A \<longmapsto> B \<subseteq> program" |
15634 | 164 |
by (unfold leadsTo_def, auto) |
165 |
||
46953 | 166 |
lemma leadsToD2: |
61392 | 167 |
"F \<in> A \<longmapsto> B ==> F \<in> program & st_set(A) & st_set(B)" |
15634 | 168 |
apply (unfold leadsTo_def st_set_def) |
169 |
apply (blast dest: leads_left leads_right) |
|
170 |
done |
|
171 |
||
46953 | 172 |
lemma leadsTo_Basis: |
61392 | 173 |
"[|F \<in> A ensures B; st_set(A); st_set(B)|] ==> F \<in> A \<longmapsto> B" |
15634 | 174 |
apply (unfold leadsTo_def st_set_def) |
175 |
apply (cut_tac ensures_type) |
|
176 |
apply (auto intro: leads.Basis) |
|
177 |
done |
|
178 |
declare leadsTo_Basis [intro] |
|
179 |
||
180 |
(* Added by Sidi, from Misra's notes, Progress chapter, exercise number 4 *) |
|
61392 | 181 |
(* [| F \<in> program; A<=B; st_set(A); st_set(B) |] ==> A \<longmapsto> B *) |
45602 | 182 |
lemmas subset_imp_leadsTo = subset_imp_ensures [THEN leadsTo_Basis] |
15634 | 183 |
|
61392 | 184 |
lemma leadsTo_Trans: "[|F \<in> A \<longmapsto> B; F \<in> B \<longmapsto> C |]==>F \<in> A \<longmapsto> C" |
15634 | 185 |
apply (unfold leadsTo_def) |
186 |
apply (auto intro: leads.Trans) |
|
187 |
done |
|
188 |
||
189 |
(* Better when used in association with leadsTo_weaken_R *) |
|
61392 | 190 |
lemma transient_imp_leadsTo: "F \<in> transient(A) ==> F \<in> A \<longmapsto> (state-A)" |
15634 | 191 |
apply (unfold transient_def) |
192 |
apply (blast intro: ensuresI [THEN leadsTo_Basis] constrains_weaken transientI) |
|
193 |
done |
|
194 |
||
195 |
(*Useful with cancellation, disjunction*) |
|
61392 | 196 |
lemma leadsTo_Un_duplicate: "F \<in> A \<longmapsto> (A' \<union> A') ==> F \<in> A \<longmapsto> A'" |
15634 | 197 |
by simp |
198 |
||
199 |
lemma leadsTo_Un_duplicate2: |
|
61392 | 200 |
"F \<in> A \<longmapsto> (A' \<union> C \<union> C) ==> F \<in> A \<longmapsto> (A' \<union> C)" |
15634 | 201 |
by (simp add: Un_ac) |
202 |
||
203 |
(*The Union introduction rule as we should have liked to state it*) |
|
46953 | 204 |
lemma leadsTo_Union: |
61392 | 205 |
"[|!!A. A \<in> S ==> F \<in> A \<longmapsto> B; F \<in> program; st_set(B)|] |
206 |
==> F \<in> \<Union>(S) \<longmapsto> B" |
|
15634 | 207 |
apply (unfold leadsTo_def st_set_def) |
208 |
apply (blast intro: leads.Union dest: leads_left) |
|
209 |
done |
|
210 |
||
46953 | 211 |
lemma leadsTo_Union_Int: |
61392 | 212 |
"[|!!A. A \<in> S ==>F \<in> (A \<inter> C) \<longmapsto> B; F \<in> program; st_set(B)|] |
213 |
==> F \<in> (\<Union>(S)Int C)\<longmapsto> B" |
|
15634 | 214 |
apply (unfold leadsTo_def st_set_def) |
215 |
apply (simp only: Int_Union_Union) |
|
216 |
apply (blast dest: leads_left intro: leads.Union) |
|
217 |
done |
|
218 |
||
46953 | 219 |
lemma leadsTo_UN: |
61392 | 220 |
"[| !!i. i \<in> I ==> F \<in> A(i) \<longmapsto> B; F \<in> program; st_set(B)|] |
221 |
==> F:(\<Union>i \<in> I. A(i)) \<longmapsto> B" |
|
15634 | 222 |
apply (simp add: Int_Union_Union leadsTo_def st_set_def) |
223 |
apply (blast dest: leads_left intro: leads.Union) |
|
224 |
done |
|
225 |
||
226 |
(* Binary union introduction rule *) |
|
227 |
lemma leadsTo_Un: |
|
61392 | 228 |
"[| F \<in> A \<longmapsto> C; F \<in> B \<longmapsto> C |] ==> F \<in> (A \<union> B) \<longmapsto> C" |
15634 | 229 |
apply (subst Un_eq_Union) |
230 |
apply (blast intro: leadsTo_Union dest: leadsToD2) |
|
231 |
done |
|
232 |
||
233 |
lemma single_leadsTo_I: |
|
61392 | 234 |
"[|!!x. x \<in> A==> F:{x} \<longmapsto> B; F \<in> program; st_set(B) |] |
235 |
==> F \<in> A \<longmapsto> B" |
|
15634 | 236 |
apply (rule_tac b = A in UN_singleton [THEN subst]) |
46953 | 237 |
apply (rule leadsTo_UN, auto) |
15634 | 238 |
done |
239 |
||
61392 | 240 |
lemma leadsTo_refl: "[| F \<in> program; st_set(A) |] ==> F \<in> A \<longmapsto> A" |
15634 | 241 |
by (blast intro: subset_imp_leadsTo) |
242 |
||
61392 | 243 |
lemma leadsTo_refl_iff: "F \<in> A \<longmapsto> A \<longleftrightarrow> F \<in> program & st_set(A)" |
15634 | 244 |
by (auto intro: leadsTo_refl dest: leadsToD2) |
245 |
||
61392 | 246 |
lemma empty_leadsTo: "F \<in> 0 \<longmapsto> B \<longleftrightarrow> (F \<in> program & st_set(B))" |
15634 | 247 |
by (auto intro: subset_imp_leadsTo dest: leadsToD2) |
248 |
declare empty_leadsTo [iff] |
|
249 |
||
61392 | 250 |
lemma leadsTo_state: "F \<in> A \<longmapsto> state \<longleftrightarrow> (F \<in> program & st_set(A))" |
15634 | 251 |
by (auto intro: subset_imp_leadsTo dest: leadsToD2 st_setD) |
252 |
declare leadsTo_state [iff] |
|
253 |
||
61392 | 254 |
lemma leadsTo_weaken_R: "[| F \<in> A \<longmapsto> A'; A'<=B'; st_set(B') |] ==> F \<in> A \<longmapsto> B'" |
15634 | 255 |
by (blast dest: leadsToD2 intro: subset_imp_leadsTo leadsTo_Trans) |
256 |
||
61392 | 257 |
lemma leadsTo_weaken_L: "[| F \<in> A \<longmapsto> A'; B<=A |] ==> F \<in> B \<longmapsto> A'" |
15634 | 258 |
apply (frule leadsToD2) |
259 |
apply (blast intro: leadsTo_Trans subset_imp_leadsTo st_set_subset) |
|
260 |
done |
|
261 |
||
61392 | 262 |
lemma leadsTo_weaken: "[| F \<in> A \<longmapsto> A'; B<=A; A'<=B'; st_set(B')|]==> F \<in> B \<longmapsto> B'" |
15634 | 263 |
apply (frule leadsToD2) |
264 |
apply (blast intro: leadsTo_weaken_R leadsTo_weaken_L leadsTo_Trans leadsTo_refl) |
|
265 |
done |
|
266 |
||
267 |
(* This rule has a nicer conclusion *) |
|
61392 | 268 |
lemma transient_imp_leadsTo2: "[| F \<in> transient(A); state-A<=B; st_set(B)|] ==> F \<in> A \<longmapsto> B" |
15634 | 269 |
apply (frule transientD2) |
270 |
apply (rule leadsTo_weaken_R) |
|
271 |
apply (auto simp add: transient_imp_leadsTo) |
|
272 |
done |
|
273 |
||
274 |
(*Distributes over binary unions*) |
|
61392 | 275 |
lemma leadsTo_Un_distrib: "F:(A \<union> B) \<longmapsto> C \<longleftrightarrow> (F \<in> A \<longmapsto> C & F \<in> B \<longmapsto> C)" |
15634 | 276 |
by (blast intro: leadsTo_Un leadsTo_weaken_L) |
277 |
||
46953 | 278 |
lemma leadsTo_UN_distrib: |
61392 | 279 |
"(F:(\<Union>i \<in> I. A(i)) \<longmapsto> B)\<longleftrightarrow> ((\<forall>i \<in> I. F \<in> A(i) \<longmapsto> B) & F \<in> program & st_set(B))" |
15634 | 280 |
apply (blast dest: leadsToD2 intro: leadsTo_UN leadsTo_weaken_L) |
281 |
done |
|
282 |
||
61392 | 283 |
lemma leadsTo_Union_distrib: "(F \<in> \<Union>(S) \<longmapsto> B) \<longleftrightarrow> (\<forall>A \<in> S. F \<in> A \<longmapsto> B) & F \<in> program & st_set(B)" |
15634 | 284 |
by (blast dest: leadsToD2 intro: leadsTo_Union leadsTo_weaken_L) |
285 |
||
61798 | 286 |
text\<open>Set difference: maybe combine with \<open>leadsTo_weaken_L\<close>??\<close> |
15634 | 287 |
lemma leadsTo_Diff: |
61392 | 288 |
"[| F: (A-B) \<longmapsto> C; F \<in> B \<longmapsto> C; st_set(C) |] |
289 |
==> F \<in> A \<longmapsto> C" |
|
15634 | 290 |
by (blast intro: leadsTo_Un leadsTo_weaken dest: leadsToD2) |
291 |
||
292 |
lemma leadsTo_UN_UN: |
|
61392 | 293 |
"[|!!i. i \<in> I ==> F \<in> A(i) \<longmapsto> A'(i); F \<in> program |] |
294 |
==> F: (\<Union>i \<in> I. A(i)) \<longmapsto> (\<Union>i \<in> I. A'(i))" |
|
15634 | 295 |
apply (rule leadsTo_Union) |
46953 | 296 |
apply (auto intro: leadsTo_weaken_R dest: leadsToD2) |
15634 | 297 |
done |
298 |
||
299 |
(*Binary union version*) |
|
61392 | 300 |
lemma leadsTo_Un_Un: "[| F \<in> A \<longmapsto> A'; F \<in> B \<longmapsto> B' |] ==> F \<in> (A \<union> B) \<longmapsto> (A' \<union> B')" |
15634 | 301 |
apply (subgoal_tac "st_set (A) & st_set (A') & st_set (B) & st_set (B') ") |
302 |
prefer 2 apply (blast dest: leadsToD2) |
|
303 |
apply (blast intro: leadsTo_Un leadsTo_weaken_R) |
|
304 |
done |
|
305 |
||
306 |
(** The cancellation law **) |
|
61392 | 307 |
lemma leadsTo_cancel2: "[|F \<in> A \<longmapsto> (A' \<union> B); F \<in> B \<longmapsto> B'|] ==> F \<in> A \<longmapsto> (A' \<union> B')" |
15634 | 308 |
apply (subgoal_tac "st_set (A) & st_set (A') & st_set (B) & st_set (B') &F \<in> program") |
309 |
prefer 2 apply (blast dest: leadsToD2) |
|
310 |
apply (blast intro: leadsTo_Trans leadsTo_Un_Un leadsTo_refl) |
|
311 |
done |
|
312 |
||
61392 | 313 |
lemma leadsTo_cancel_Diff2: "[|F \<in> A \<longmapsto> (A' \<union> B); F \<in> (B-A') \<longmapsto> B'|]==> F \<in> A \<longmapsto> (A' \<union> B')" |
15634 | 314 |
apply (rule leadsTo_cancel2) |
315 |
prefer 2 apply assumption |
|
316 |
apply (blast dest: leadsToD2 intro: leadsTo_weaken_R) |
|
317 |
done |
|
318 |
||
319 |
||
61392 | 320 |
lemma leadsTo_cancel1: "[| F \<in> A \<longmapsto> (B \<union> A'); F \<in> B \<longmapsto> B' |] ==> F \<in> A \<longmapsto> (B' \<union> A')" |
15634 | 321 |
apply (simp add: Un_commute) |
322 |
apply (blast intro!: leadsTo_cancel2) |
|
323 |
done |
|
324 |
||
325 |
lemma leadsTo_cancel_Diff1: |
|
61392 | 326 |
"[|F \<in> A \<longmapsto> (B \<union> A'); F: (B-A') \<longmapsto> B'|]==> F \<in> A \<longmapsto> (B' \<union> A')" |
15634 | 327 |
apply (rule leadsTo_cancel1) |
328 |
prefer 2 apply assumption |
|
329 |
apply (blast intro: leadsTo_weaken_R dest: leadsToD2) |
|
330 |
done |
|
331 |
||
332 |
(*The INDUCTION rule as we should have liked to state it*) |
|
333 |
lemma leadsTo_induct: |
|
61392 | 334 |
assumes major: "F \<in> za \<longmapsto> zb" |
15634 | 335 |
and basis: "!!A B. [|F \<in> A ensures B; st_set(A); st_set(B)|] ==> P(A,B)" |
61392 | 336 |
and trans: "!!A B C. [| F \<in> A \<longmapsto> B; P(A, B); |
337 |
F \<in> B \<longmapsto> C; P(B, C) |] ==> P(A,C)" |
|
338 |
and union: "!!B S. [| \<forall>A \<in> S. F \<in> A \<longmapsto> B; \<forall>A \<in> S. P(A,B); |
|
46823 | 339 |
st_set(B); \<forall>A \<in> S. st_set(A)|] ==> P(\<Union>(S), B)" |
15634 | 340 |
shows "P(za, zb)" |
341 |
apply (cut_tac major) |
|
46953 | 342 |
apply (unfold leadsTo_def, clarify) |
343 |
apply (erule leads.induct) |
|
15634 | 344 |
apply (blast intro: basis [unfolded st_set_def]) |
46953 | 345 |
apply (blast intro: trans [unfolded leadsTo_def]) |
346 |
apply (force intro: union [unfolded st_set_def leadsTo_def]) |
|
15634 | 347 |
done |
348 |
||
349 |
||
350 |
(* Added by Sidi, an induction rule without ensures *) |
|
351 |
lemma leadsTo_induct2: |
|
61392 | 352 |
assumes major: "F \<in> za \<longmapsto> zb" |
15634 | 353 |
and basis1: "!!A B. [| A<=B; st_set(B) |] ==> P(A, B)" |
46953 | 354 |
and basis2: "!!A B. [| F \<in> A co A \<union> B; F \<in> transient(A); st_set(B) |] |
15634 | 355 |
==> P(A, B)" |
61392 | 356 |
and trans: "!!A B C. [| F \<in> A \<longmapsto> B; P(A, B); |
357 |
F \<in> B \<longmapsto> C; P(B, C) |] ==> P(A,C)" |
|
358 |
and union: "!!B S. [| \<forall>A \<in> S. F \<in> A \<longmapsto> B; \<forall>A \<in> S. P(A,B); |
|
46823 | 359 |
st_set(B); \<forall>A \<in> S. st_set(A)|] ==> P(\<Union>(S), B)" |
15634 | 360 |
shows "P(za, zb)" |
361 |
apply (cut_tac major) |
|
362 |
apply (erule leadsTo_induct) |
|
363 |
apply (auto intro: trans union) |
|
364 |
apply (simp add: ensures_def, clarify) |
|
365 |
apply (frule constrainsD2) |
|
46823 | 366 |
apply (drule_tac B' = " (A-B) \<union> B" in constrains_weaken_R) |
15634 | 367 |
apply blast |
368 |
apply (frule ensuresI2 [THEN leadsTo_Basis]) |
|
369 |
apply (drule_tac [4] basis2, simp_all) |
|
370 |
apply (frule_tac A1 = A and B = B in Int_lower2 [THEN basis1]) |
|
46823 | 371 |
apply (subgoal_tac "A=\<Union>({A - B, A \<inter> B}) ") |
15634 | 372 |
prefer 2 apply blast |
373 |
apply (erule ssubst) |
|
374 |
apply (rule union) |
|
375 |
apply (auto intro: subset_imp_leadsTo) |
|
376 |
done |
|
377 |
||
378 |
||
379 |
(** Variant induction rule: on the preconditions for B **) |
|
380 |
(*Lemma is the weak version: can't see how to do it in one step*) |
|
46953 | 381 |
lemma leadsTo_induct_pre_aux: |
61392 | 382 |
"[| F \<in> za \<longmapsto> zb; |
46953 | 383 |
P(zb); |
384 |
!!A B. [| F \<in> A ensures B; P(B); st_set(A); st_set(B) |] ==> P(A); |
|
385 |
!!S. [| \<forall>A \<in> S. P(A); \<forall>A \<in> S. st_set(A) |] ==> P(\<Union>(S)) |
|
15634 | 386 |
|] ==> P(za)" |
60770 | 387 |
txt\<open>by induction on this formula\<close> |
46823 | 388 |
apply (subgoal_tac "P (zb) \<longrightarrow> P (za) ") |
60770 | 389 |
txt\<open>now solve first subgoal: this formula is sufficient\<close> |
15634 | 390 |
apply (blast intro: leadsTo_refl) |
391 |
apply (erule leadsTo_induct) |
|
392 |
apply (blast+) |
|
393 |
done |
|
394 |
||
395 |
||
46953 | 396 |
lemma leadsTo_induct_pre: |
61392 | 397 |
"[| F \<in> za \<longmapsto> zb; |
46953 | 398 |
P(zb); |
61392 | 399 |
!!A B. [| F \<in> A ensures B; F \<in> B \<longmapsto> zb; P(B); st_set(A) |] ==> P(A); |
400 |
!!S. \<forall>A \<in> S. F \<in> A \<longmapsto> zb & P(A) & st_set(A) ==> P(\<Union>(S)) |
|
15634 | 401 |
|] ==> P(za)" |
61392 | 402 |
apply (subgoal_tac " (F \<in> za \<longmapsto> zb) & P (za) ") |
15634 | 403 |
apply (erule conjunct2) |
46953 | 404 |
apply (frule leadsToD2) |
15634 | 405 |
apply (erule leadsTo_induct_pre_aux) |
406 |
prefer 3 apply (blast dest: leadsToD2 intro: leadsTo_Union) |
|
407 |
prefer 2 apply (blast intro: leadsTo_Trans leadsTo_Basis) |
|
408 |
apply (blast intro: leadsTo_refl) |
|
409 |
done |
|
410 |
||
411 |
(** The impossibility law **) |
|
46953 | 412 |
lemma leadsTo_empty: |
61392 | 413 |
"F \<in> A \<longmapsto> 0 ==> A=0" |
15634 | 414 |
apply (erule leadsTo_induct_pre) |
415 |
apply (auto simp add: ensures_def constrains_def transient_def st_set_def) |
|
416 |
apply (drule bspec, assumption)+ |
|
417 |
apply blast |
|
418 |
done |
|
419 |
declare leadsTo_empty [simp] |
|
420 |
||
60770 | 421 |
subsection\<open>PSP: Progress-Safety-Progress\<close> |
15634 | 422 |
|
60770 | 423 |
text\<open>Special case of PSP: Misra's "stable conjunction"\<close> |
15634 | 424 |
|
46953 | 425 |
lemma psp_stable: |
61392 | 426 |
"[| F \<in> A \<longmapsto> A'; F \<in> stable(B) |] ==> F:(A \<inter> B) \<longmapsto> (A' \<inter> B)" |
15634 | 427 |
apply (unfold stable_def) |
46953 | 428 |
apply (frule leadsToD2) |
15634 | 429 |
apply (erule leadsTo_induct) |
430 |
prefer 3 apply (blast intro: leadsTo_Union_Int) |
|
431 |
prefer 2 apply (blast intro: leadsTo_Trans) |
|
432 |
apply (rule leadsTo_Basis) |
|
433 |
apply (simp add: ensures_def Diff_Int_distrib2 [symmetric] Int_Un_distrib2 [symmetric]) |
|
434 |
apply (auto intro: transient_strengthen constrains_Int) |
|
435 |
done |
|
436 |
||
437 |
||
61392 | 438 |
lemma psp_stable2: "[|F \<in> A \<longmapsto> A'; F \<in> stable(B) |]==>F: (B \<inter> A) \<longmapsto> (B \<inter> A')" |
15634 | 439 |
apply (simp (no_asm_simp) add: psp_stable Int_ac) |
440 |
done |
|
441 |
||
46953 | 442 |
lemma psp_ensures: |
46823 | 443 |
"[| F \<in> A ensures A'; F \<in> B co B' |]==> F: (A \<inter> B') ensures ((A' \<inter> B) \<union> (B' - B))" |
15634 | 444 |
apply (unfold ensures_def constrains_def st_set_def) |
445 |
(*speeds up the proof*) |
|
446 |
apply clarify |
|
447 |
apply (blast intro: transient_strengthen) |
|
448 |
done |
|
449 |
||
46953 | 450 |
lemma psp: |
61392 | 451 |
"[|F \<in> A \<longmapsto> A'; F \<in> B co B'; st_set(B')|]==> F:(A \<inter> B') \<longmapsto> ((A' \<inter> B) \<union> (B' - B))" |
15634 | 452 |
apply (subgoal_tac "F \<in> program & st_set (A) & st_set (A') & st_set (B) ") |
453 |
prefer 2 apply (blast dest!: constrainsD2 leadsToD2) |
|
454 |
apply (erule leadsTo_induct) |
|
455 |
prefer 3 apply (blast intro: leadsTo_Union_Int) |
|
60770 | 456 |
txt\<open>Basis case\<close> |
15634 | 457 |
apply (blast intro: psp_ensures leadsTo_Basis) |
60770 | 458 |
txt\<open>Transitivity case has a delicate argument involving "cancellation"\<close> |
15634 | 459 |
apply (rule leadsTo_Un_duplicate2) |
460 |
apply (erule leadsTo_cancel_Diff1) |
|
461 |
apply (simp add: Int_Diff Diff_triv) |
|
462 |
apply (blast intro: leadsTo_weaken_L dest: constrains_imp_subset) |
|
463 |
done |
|
464 |
||
465 |
||
61392 | 466 |
lemma psp2: "[| F \<in> A \<longmapsto> A'; F \<in> B co B'; st_set(B') |] |
467 |
==> F \<in> (B' \<inter> A) \<longmapsto> ((B \<inter> A') \<union> (B' - B))" |
|
15634 | 468 |
by (simp (no_asm_simp) add: psp Int_ac) |
469 |
||
46953 | 470 |
lemma psp_unless: |
61392 | 471 |
"[| F \<in> A \<longmapsto> A'; F \<in> B unless B'; st_set(B); st_set(B') |] |
472 |
==> F \<in> (A \<inter> B) \<longmapsto> ((A' \<inter> B) \<union> B')" |
|
15634 | 473 |
apply (unfold unless_def) |
474 |
apply (subgoal_tac "st_set (A) &st_set (A') ") |
|
475 |
prefer 2 apply (blast dest: leadsToD2) |
|
476 |
apply (drule psp, assumption, blast) |
|
477 |
apply (blast intro: leadsTo_weaken) |
|
478 |
done |
|
479 |
||
480 |
||
60770 | 481 |
subsection\<open>Proving the induction rules\<close> |
15634 | 482 |
|
483 |
(** The most general rule \<in> r is any wf relation; f is any variant function **) |
|
46953 | 484 |
lemma leadsTo_wf_induct_aux: "[| wf(r); |
485 |
m \<in> I; |
|
486 |
field(r)<=I; |
|
487 |
F \<in> program; st_set(B); |
|
61392 | 488 |
\<forall>m \<in> I. F \<in> (A \<inter> f-``{m}) \<longmapsto> |
46953 | 489 |
((A \<inter> f-``(converse(r)``{m})) \<union> B) |] |
61392 | 490 |
==> F \<in> (A \<inter> f-``{m}) \<longmapsto> B" |
15634 | 491 |
apply (erule_tac a = m in wf_induct2, simp_all) |
61392 | 492 |
apply (subgoal_tac "F \<in> (A \<inter> (f-`` (converse (r) ``{x}))) \<longmapsto> B") |
15634 | 493 |
apply (blast intro: leadsTo_cancel1 leadsTo_Un_duplicate) |
494 |
apply (subst vimage_eq_UN) |
|
495 |
apply (simp del: UN_simps add: Int_UN_distrib) |
|
496 |
apply (auto intro: leadsTo_UN simp del: UN_simps simp add: Int_UN_distrib) |
|
497 |
done |
|
498 |
||
499 |
(** Meta or object quantifier ? **) |
|
46953 | 500 |
lemma leadsTo_wf_induct: "[| wf(r); |
501 |
field(r)<=I; |
|
502 |
A<=f-``I; |
|
503 |
F \<in> program; st_set(A); st_set(B); |
|
61392 | 504 |
\<forall>m \<in> I. F \<in> (A \<inter> f-``{m}) \<longmapsto> |
46953 | 505 |
((A \<inter> f-``(converse(r)``{m})) \<union> B) |] |
61392 | 506 |
==> F \<in> A \<longmapsto> B" |
15634 | 507 |
apply (rule_tac b = A in subst) |
508 |
defer 1 |
|
509 |
apply (rule_tac I = I in leadsTo_UN) |
|
46953 | 510 |
apply (erule_tac I = I in leadsTo_wf_induct_aux, assumption+, best) |
15634 | 511 |
done |
512 |
||
513 |
lemma nat_measure_field: "field(measure(nat, %x. x)) = nat" |
|
514 |
apply (unfold field_def) |
|
515 |
apply (simp add: measure_def) |
|
516 |
apply (rule equalityI, force, clarify) |
|
59788 | 517 |
apply (erule_tac V = "x\<notin>range (y)" for y in thin_rl) |
15634 | 518 |
apply (erule nat_induct) |
519 |
apply (rule_tac [2] b = "succ (succ (xa))" in domainI) |
|
520 |
apply (rule_tac b = "succ (0) " in domainI) |
|
521 |
apply simp_all |
|
522 |
done |
|
523 |
||
524 |
||
525 |
lemma Image_inverse_lessThan: "k<A ==> measure(A, %x. x) -`` {k} = k" |
|
526 |
apply (rule equalityI) |
|
527 |
apply (auto simp add: measure_def) |
|
528 |
apply (blast intro: ltD) |
|
529 |
apply (rule vimageI) |
|
530 |
prefer 2 apply blast |
|
531 |
apply (simp add: lt_Ord lt_Ord2 Ord_mem_iff_lt) |
|
532 |
apply (blast intro: lt_trans) |
|
533 |
done |
|
534 |
||
61392 | 535 |
(*Alternative proof is via the lemma F \<in> (A \<inter> f-`(lessThan m)) \<longmapsto> B*) |
46953 | 536 |
lemma lessThan_induct: |
537 |
"[| A<=f-``nat; |
|
538 |
F \<in> program; st_set(A); st_set(B); |
|
61392 | 539 |
\<forall>m \<in> nat. F:(A \<inter> f-``{m}) \<longmapsto> ((A \<inter> f -`` m) \<union> B) |] |
540 |
==> F \<in> A \<longmapsto> B" |
|
46953 | 541 |
apply (rule_tac A1 = nat and f1 = "%x. x" in wf_measure [THEN leadsTo_wf_induct]) |
15634 | 542 |
apply (simp_all add: nat_measure_field) |
543 |
apply (simp add: ltI Image_inverse_lessThan vimage_def [symmetric]) |
|
544 |
done |
|
545 |
||
546 |
||
547 |
(*** wlt ****) |
|
548 |
||
549 |
(*Misra's property W3*) |
|
550 |
lemma wlt_type: "wlt(F,B) <=state" |
|
551 |
by (unfold wlt_def, auto) |
|
552 |
||
553 |
lemma wlt_st_set: "st_set(wlt(F, B))" |
|
554 |
apply (unfold st_set_def) |
|
555 |
apply (rule wlt_type) |
|
556 |
done |
|
557 |
declare wlt_st_set [iff] |
|
558 |
||
61392 | 559 |
lemma wlt_leadsTo_iff: "F \<in> wlt(F, B) \<longmapsto> B \<longleftrightarrow> (F \<in> program & st_set(B))" |
15634 | 560 |
apply (unfold wlt_def) |
561 |
apply (blast dest: leadsToD2 intro!: leadsTo_Union) |
|
562 |
done |
|
563 |
||
61392 | 564 |
(* [| F \<in> program; st_set(B) |] ==> F \<in> wlt(F, B) \<longmapsto> B *) |
45602 | 565 |
lemmas wlt_leadsTo = conjI [THEN wlt_leadsTo_iff [THEN iffD2]] |
15634 | 566 |
|
61392 | 567 |
lemma leadsTo_subset: "F \<in> A \<longmapsto> B ==> A \<subseteq> wlt(F, B)" |
15634 | 568 |
apply (unfold wlt_def) |
569 |
apply (frule leadsToD2) |
|
570 |
apply (auto simp add: st_set_def) |
|
571 |
done |
|
572 |
||
573 |
(*Misra's property W2*) |
|
61392 | 574 |
lemma leadsTo_eq_subset_wlt: "F \<in> A \<longmapsto> B \<longleftrightarrow> (A \<subseteq> wlt(F,B) & F \<in> program & st_set(B))" |
15634 | 575 |
apply auto |
576 |
apply (blast dest: leadsToD2 leadsTo_subset intro: leadsTo_weaken_L wlt_leadsTo)+ |
|
577 |
done |
|
578 |
||
579 |
(*Misra's property W4*) |
|
46823 | 580 |
lemma wlt_increasing: "[| F \<in> program; st_set(B) |] ==> B \<subseteq> wlt(F,B)" |
15634 | 581 |
apply (rule leadsTo_subset) |
582 |
apply (simp (no_asm_simp) add: leadsTo_eq_subset_wlt [THEN iff_sym] subset_imp_leadsTo) |
|
583 |
done |
|
584 |
||
585 |
(*Used in the Trans case below*) |
|
46953 | 586 |
lemma leadsTo_123_aux: |
587 |
"[| B \<subseteq> A2; |
|
588 |
F \<in> (A1 - B) co (A1 \<union> B); |
|
589 |
F \<in> (A2 - C) co (A2 \<union> C) |] |
|
46823 | 590 |
==> F \<in> (A1 \<union> A2 - C) co (A1 \<union> A2 \<union> C)" |
15634 | 591 |
apply (unfold constrains_def st_set_def, blast) |
592 |
done |
|
593 |
||
594 |
(*Lemma (1,2,3) of Misra's draft book, Chapter 4, "Progress"*) |
|
595 |
(* slightly different from the HOL one \<in> B here is bounded *) |
|
61392 | 596 |
lemma leadsTo_123: "F \<in> A \<longmapsto> A' |
597 |
==> \<exists>B \<in> Pow(state). A<=B & F \<in> B \<longmapsto> A' & F \<in> (B-A') co (B \<union> A')" |
|
15634 | 598 |
apply (frule leadsToD2) |
599 |
apply (erule leadsTo_induct) |
|
60770 | 600 |
txt\<open>Basis\<close> |
15634 | 601 |
apply (blast dest: ensuresD constrainsD2 st_setD) |
60770 | 602 |
txt\<open>Trans\<close> |
15634 | 603 |
apply clarify |
46823 | 604 |
apply (rule_tac x = "Ba \<union> Bb" in bexI) |
15634 | 605 |
apply (blast intro: leadsTo_123_aux leadsTo_Un_Un leadsTo_cancel1 leadsTo_Un_duplicate, blast) |
60770 | 606 |
txt\<open>Union\<close> |
15634 | 607 |
apply (clarify dest!: ball_conj_distrib [THEN iffD1]) |
61392 | 608 |
apply (subgoal_tac "\<exists>y. y \<in> Pi (S, %A. {Ba \<in> Pow (state) . A<=Ba & F \<in> Ba \<longmapsto> B & F \<in> Ba - B co Ba \<union> B}) ") |
15634 | 609 |
defer 1 |
610 |
apply (rule AC_ball_Pi, safe) |
|
611 |
apply (rotate_tac 1) |
|
46953 | 612 |
apply (drule_tac x = x in bspec, blast, blast) |
15634 | 613 |
apply (rule_tac x = "\<Union>A \<in> S. y`A" in bexI, safe) |
614 |
apply (rule_tac [3] I1 = S in constrains_UN [THEN constrains_weaken]) |
|
615 |
apply (rule_tac [2] leadsTo_Union) |
|
616 |
prefer 5 apply (blast dest!: apply_type, simp_all) |
|
617 |
apply (force dest!: apply_type)+ |
|
618 |
done |
|
619 |
||
620 |
||
621 |
(*Misra's property W5*) |
|
622 |
lemma wlt_constrains_wlt: "[| F \<in> program; st_set(B) |] ==>F \<in> (wlt(F, B) - B) co (wlt(F,B))" |
|
623 |
apply (cut_tac F = F in wlt_leadsTo [THEN leadsTo_123], assumption, blast) |
|
624 |
apply clarify |
|
625 |
apply (subgoal_tac "Ba = wlt (F,B) ") |
|
626 |
prefer 2 apply (blast dest: leadsTo_eq_subset_wlt [THEN iffD1], clarify) |
|
627 |
apply (simp add: wlt_increasing [THEN subset_Un_iff2 [THEN iffD1]]) |
|
628 |
done |
|
629 |
||
630 |
||
60770 | 631 |
subsection\<open>Completion: Binary and General Finite versions\<close> |
15634 | 632 |
|
46953 | 633 |
lemma completion_aux: "[| W = wlt(F, (B' \<union> C)); |
61392 | 634 |
F \<in> A \<longmapsto> (A' \<union> C); F \<in> A' co (A' \<union> C); |
635 |
F \<in> B \<longmapsto> (B' \<union> C); F \<in> B' co (B' \<union> C) |] |
|
636 |
==> F \<in> (A \<inter> B) \<longmapsto> ((A' \<inter> B') \<union> C)" |
|
15634 | 637 |
apply (subgoal_tac "st_set (C) &st_set (W) &st_set (W-C) &st_set (A') &st_set (A) & st_set (B) & st_set (B') & F \<in> program") |
46953 | 638 |
prefer 2 |
639 |
apply simp |
|
15634 | 640 |
apply (blast dest!: leadsToD2) |
46823 | 641 |
apply (subgoal_tac "F \<in> (W-C) co (W \<union> B' \<union> C) ") |
15634 | 642 |
prefer 2 |
643 |
apply (blast intro!: constrains_weaken [OF constrains_Un [OF _ wlt_constrains_wlt]]) |
|
644 |
apply (subgoal_tac "F \<in> (W-C) co W") |
|
645 |
prefer 2 |
|
646 |
apply (simp add: wlt_increasing [THEN subset_Un_iff2 [THEN iffD1]] Un_assoc) |
|
61392 | 647 |
apply (subgoal_tac "F \<in> (A \<inter> W - C) \<longmapsto> (A' \<inter> W \<union> C) ") |
15634 | 648 |
prefer 2 apply (blast intro: wlt_leadsTo psp [THEN leadsTo_weaken]) |
649 |
(** step 13 **) |
|
61392 | 650 |
apply (subgoal_tac "F \<in> (A' \<inter> W \<union> C) \<longmapsto> (A' \<inter> B' \<union> C) ") |
15634 | 651 |
apply (drule leadsTo_Diff) |
652 |
apply (blast intro: subset_imp_leadsTo dest: leadsToD2 constrainsD2) |
|
653 |
apply (force simp add: st_set_def) |
|
46823 | 654 |
apply (subgoal_tac "A \<inter> B \<subseteq> A \<inter> W") |
15634 | 655 |
prefer 2 apply (blast dest!: leadsTo_subset intro!: subset_refl [THEN Int_mono]) |
656 |
apply (blast intro: leadsTo_Trans subset_imp_leadsTo) |
|
60770 | 657 |
txt\<open>last subgoal\<close> |
15634 | 658 |
apply (rule_tac leadsTo_Un_duplicate2) |
659 |
apply (rule_tac leadsTo_Un_Un) |
|
660 |
prefer 2 apply (blast intro: leadsTo_refl) |
|
46823 | 661 |
apply (rule_tac A'1 = "B' \<union> C" in wlt_leadsTo[THEN psp2, THEN leadsTo_weaken]) |
15634 | 662 |
apply blast+ |
663 |
done |
|
664 |
||
45602 | 665 |
lemmas completion = refl [THEN completion_aux] |
15634 | 666 |
|
667 |
lemma finite_completion_aux: |
|
46953 | 668 |
"[| I \<in> Fin(X); F \<in> program; st_set(C) |] ==> |
61392 | 669 |
(\<forall>i \<in> I. F \<in> (A(i)) \<longmapsto> (A'(i) \<union> C)) \<longrightarrow> |
46953 | 670 |
(\<forall>i \<in> I. F \<in> (A'(i)) co (A'(i) \<union> C)) \<longrightarrow> |
61392 | 671 |
F \<in> (\<Inter>i \<in> I. A(i)) \<longmapsto> ((\<Inter>i \<in> I. A'(i)) \<union> C)" |
15634 | 672 |
apply (erule Fin_induct) |
673 |
apply (auto simp add: Inter_0) |
|
674 |
apply (rule completion) |
|
675 |
apply (auto simp del: INT_simps simp add: INT_extend_simps) |
|
676 |
apply (blast intro: constrains_INT) |
|
677 |
done |
|
678 |
||
46953 | 679 |
lemma finite_completion: |
680 |
"[| I \<in> Fin(X); |
|
61392 | 681 |
!!i. i \<in> I ==> F \<in> A(i) \<longmapsto> (A'(i) \<union> C); |
46953 | 682 |
!!i. i \<in> I ==> F \<in> A'(i) co (A'(i) \<union> C); F \<in> program; st_set(C)|] |
61392 | 683 |
==> F \<in> (\<Inter>i \<in> I. A(i)) \<longmapsto> ((\<Inter>i \<in> I. A'(i)) \<union> C)" |
15634 | 684 |
by (blast intro: finite_completion_aux [THEN mp, THEN mp]) |
685 |
||
46953 | 686 |
lemma stable_completion: |
61392 | 687 |
"[| F \<in> A \<longmapsto> A'; F \<in> stable(A'); |
688 |
F \<in> B \<longmapsto> B'; F \<in> stable(B') |] |
|
689 |
==> F \<in> (A \<inter> B) \<longmapsto> (A' \<inter> B')" |
|
15634 | 690 |
apply (unfold stable_def) |
691 |
apply (rule_tac C1 = 0 in completion [THEN leadsTo_weaken_R], simp+) |
|
692 |
apply (blast dest: leadsToD2) |
|
693 |
done |
|
694 |
||
695 |
||
46953 | 696 |
lemma finite_stable_completion: |
697 |
"[| I \<in> Fin(X); |
|
61392 | 698 |
(!!i. i \<in> I ==> F \<in> A(i) \<longmapsto> A'(i)); |
46953 | 699 |
(!!i. i \<in> I ==> F \<in> stable(A'(i))); F \<in> program |] |
61392 | 700 |
==> F \<in> (\<Inter>i \<in> I. A(i)) \<longmapsto> (\<Inter>i \<in> I. A'(i))" |
15634 | 701 |
apply (unfold stable_def) |
702 |
apply (subgoal_tac "st_set (\<Inter>i \<in> I. A' (i))") |
|
703 |
prefer 2 apply (blast dest: leadsToD2) |
|
46953 | 704 |
apply (rule_tac C1 = 0 in finite_completion [THEN leadsTo_weaken_R], auto) |
15634 | 705 |
done |
706 |
||
11479 | 707 |
end |