diff options
author | Rutger Broekhoff | 2024-06-26 20:50:18 +0200 |
---|---|---|
committer | Rutger Broekhoff | 2024-06-26 20:50:18 +0200 |
commit | 73df1945b31c0beee88cf4476df4ccd09d31403b (patch) | |
tree | ed00db26b711442e643f38b66888a3df56e33ebd /complete.v | |
download | mininix-formalization-73df1945b31c0beee88cf4476df4ccd09d31403b.tar.gz mininix-formalization-73df1945b31c0beee88cf4476df4ccd09d31403b.zip |
Import Coq project
Diffstat (limited to 'complete.v')
-rw-r--r-- | complete.v | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/complete.v b/complete.v new file mode 100644 index 0000000..9939b50 --- /dev/null +++ b/complete.v | |||
@@ -0,0 +1,413 @@ | |||
1 | Require Import Coq.Strings.String. | ||
2 | From stdpp Require Import gmap relations. | ||
3 | From mininix Require Import binop expr interpreter maptools matching sem. | ||
4 | |||
5 | Lemma eval_le n uf e v' : | ||
6 | eval n uf e = Some v' → | ||
7 | ∀ m, n ≤ m → eval m uf e = Some v'. | ||
8 | Proof. | ||
9 | revert uf e v'. | ||
10 | induction n; [discriminate|]. | ||
11 | intros uf e v' Heval [] Hle; [lia|]. | ||
12 | apply le_S_n in Hle. | ||
13 | rewrite eval_S in *. | ||
14 | destruct e; repeat (case_match || simplify_option_eq || by eauto). | ||
15 | apply bind_Some. exists H. | ||
16 | split; try by reflexivity. | ||
17 | apply map_mapM_Some_L in Heqo. | ||
18 | apply map_mapM_Some_L. | ||
19 | eapply map_Forall2_impl_L, Heqo. | ||
20 | eauto. | ||
21 | Qed. | ||
22 | |||
23 | Lemma eval_value n (v : value) : 0 < n → eval n false v = Some v. | ||
24 | Proof. destruct n, v; by try lia. Qed. | ||
25 | |||
26 | Lemma eval_strong_value n (sv : strong_value) : | ||
27 | 0 < n → | ||
28 | eval n false sv = Some (value_from_strong_value sv). | ||
29 | Proof. destruct n, sv; by try lia. Qed. | ||
30 | |||
31 | Lemma eval_force_strong_value v : ∃ n, | ||
32 | eval n true (expr_from_strong_value v) = Some (value_from_strong_value v). | ||
33 | Proof. | ||
34 | induction v using strong_value_ind'; try by exists 2. | ||
35 | unfold expr_from_strong_value. simpl. | ||
36 | fold expr_from_strong_value. | ||
37 | induction bs using map_ind. | ||
38 | + by exists 2. | ||
39 | + apply map_Forall_insert in H as [[n Hn] H2]; try done. | ||
40 | apply IHbs in H2 as [o Ho]. clear IHbs. | ||
41 | exists (S (n `max` o)). | ||
42 | rewrite eval_S. csimpl. | ||
43 | setoid_rewrite map_mapM_Some_2_L | ||
44 | with (m2 := value_from_strong_value <$> <[i := x]>m); csimpl. | ||
45 | * by rewrite <-map_fmap_compose. | ||
46 | * destruct o as [|o]; csimpl in *; try discriminate. | ||
47 | apply map_Forall2_alt_L. | ||
48 | split. | ||
49 | -- set_solver. | ||
50 | -- intros j u v ??. rewrite eval_S in Ho. | ||
51 | apply bind_Some in Ho as [vs [Ho1 Ho2]]. | ||
52 | setoid_rewrite map_mapM_Some_L in Ho1. simplify_eq. | ||
53 | unfold expr_from_strong_value in Ho2. | ||
54 | rewrite map_fmap_compose in Ho2. | ||
55 | simplify_eq. | ||
56 | destruct (decide (i = j)). | ||
57 | ++ simplify_eq. | ||
58 | repeat rewrite lookup_fmap, lookup_insert in *. | ||
59 | simplify_eq/=. | ||
60 | apply eval_le with (n := n); lia || done. | ||
61 | ++ repeat rewrite lookup_fmap, lookup_insert_ne in * by done. | ||
62 | repeat rewrite <-lookup_fmap in *. | ||
63 | apply map_Forall2_alt_L in Ho1. | ||
64 | destruct Ho1 as [Ho1 Ho2]. | ||
65 | apply eval_le with (n := o); try lia. | ||
66 | by apply Ho2 with (i := j). | ||
67 | Qed. | ||
68 | |||
69 | Lemma eval_force_strong_value' v : | ||
70 | ∃ n, eval n false (X_Force (expr_from_strong_value v)) = | ||
71 | Some (value_from_strong_value v). | ||
72 | Proof. | ||
73 | destruct (eval_force_strong_value v) as [n Heval]. | ||
74 | exists (S n). by rewrite eval_S. | ||
75 | Qed. | ||
76 | |||
77 | Lemma rec_subst_lookup bs x e : | ||
78 | bs !! x = Some (B_Nonrec e) → rec_subst bs !! x = Some e. | ||
79 | Proof. unfold rec_subst. rewrite lookup_fmap. by intros ->. Qed. | ||
80 | |||
81 | Lemma rec_subst_lookup_fmap bs x e : | ||
82 | bs !! x = Some e → rec_subst (B_Nonrec <$> bs) !! x = Some e. | ||
83 | Proof. unfold rec_subst. do 2 rewrite lookup_fmap. by intros ->. Qed. | ||
84 | |||
85 | Lemma rec_subst_lookup_fmap' bs x : | ||
86 | is_Some (bs !! x) ↔ is_Some (rec_subst (B_Nonrec <$> bs) !! x). | ||
87 | Proof. | ||
88 | unfold rec_subst. split; | ||
89 | do 2 rewrite lookup_fmap in *; | ||
90 | intros [b H]; by simplify_option_eq. | ||
91 | Qed. | ||
92 | |||
93 | Lemma eval_base_step uf e e' v'' n : | ||
94 | e -->base e' → | ||
95 | eval n uf e' = Some v'' → | ||
96 | ∃ m, eval m uf e = Some v''. | ||
97 | Proof. | ||
98 | intros [] Heval. | ||
99 | - (* E_Force *) | ||
100 | destruct uf. | ||
101 | + (* true *) | ||
102 | exists (S n). rewrite eval_S. by csimpl. | ||
103 | + (* false *) | ||
104 | destruct n; try discriminate. | ||
105 | rewrite eval_strong_value in Heval by lia. | ||
106 | simplify_option_eq. | ||
107 | apply eval_force_strong_value'. | ||
108 | - (* E_Closed *) | ||
109 | exists (S n). rewrite eval_S. by csimpl. | ||
110 | - (* E_Placeholder *) | ||
111 | exists (S n). rewrite eval_S. by csimpl. | ||
112 | - (* E_MSelect *) | ||
113 | destruct n; try discriminate. | ||
114 | rewrite eval_S in Heval. simplify_option_eq. | ||
115 | destruct ys. simplify_option_eq. | ||
116 | destruct n as [|[|n]]; try discriminate. | ||
117 | rewrite eval_S in Heqo. simplify_option_eq. | ||
118 | rewrite eval_S in Heqo1. simplify_option_eq. | ||
119 | exists (S (S (S (S n)))). rewrite eval_S. simplify_option_eq. | ||
120 | rewrite eval_value by lia. simplify_option_eq. | ||
121 | rewrite eval_S. simplify_option_eq. | ||
122 | rewrite eval_le with (n := S n) (v' := V_Attrset H0) by done || lia. | ||
123 | by simplify_option_eq. | ||
124 | - (* E_Select *) | ||
125 | exists (S n). rewrite eval_S. csimpl. | ||
126 | apply bind_Some. exists (V_Attrset (<[x := e0]>bs)). | ||
127 | destruct n; try discriminate. split; [done|]. | ||
128 | apply bind_Some. exists (<[x := e0]>bs). split; [done|]. | ||
129 | rewrite lookup_insert. by simplify_option_eq. | ||
130 | - (* E_SelectOr *) | ||
131 | destruct n; try discriminate. | ||
132 | rewrite eval_S in Heval. simplify_option_eq. | ||
133 | destruct n as [|[|n]]; try discriminate. | ||
134 | rewrite eval_S in Heqo. simplify_option_eq. | ||
135 | rewrite eval_S in Heqo0. simplify_option_eq. | ||
136 | exists (S (S (S n))). rewrite eval_S. simplify_option_eq. | ||
137 | rewrite eval_value by lia. simplify_option_eq. | ||
138 | case_match. | ||
139 | + rewrite bool_decide_eq_true in H. destruct H as [d Hd]. | ||
140 | simplify_option_eq. rewrite eval_S in Heval. simplify_option_eq. | ||
141 | rewrite eval_S in Heqo. simplify_option_eq. | ||
142 | apply eval_le with (n := S n); done || lia. | ||
143 | + rewrite bool_decide_eq_false in H. apply eq_None_not_Some in H. | ||
144 | by simplify_option_eq. | ||
145 | - (* E_MSelectOr *) | ||
146 | destruct n; try discriminate. | ||
147 | rewrite eval_S in Heval. simplify_option_eq. | ||
148 | destruct ys. simplify_option_eq. | ||
149 | destruct n as [|[|n]]; try discriminate. | ||
150 | rewrite eval_S in Heqo. simplify_option_eq. | ||
151 | rewrite eval_S in Heqo0. simplify_option_eq. | ||
152 | exists (S (S (S n))). rewrite eval_S. simplify_option_eq. | ||
153 | rewrite eval_value by lia. simplify_option_eq. | ||
154 | case_match. | ||
155 | + rewrite bool_decide_eq_true in H. destruct H as [d Hd]. | ||
156 | simplify_option_eq. rewrite eval_S in Heval. simplify_option_eq. | ||
157 | rewrite eval_S in Heqo. simplify_option_eq. | ||
158 | destruct n; try discriminate. rewrite eval_S in Heqo0. | ||
159 | simplify_option_eq. rewrite eval_S. | ||
160 | simplify_option_eq. | ||
161 | setoid_rewrite eval_le with (n := S n) (v' := V_Attrset H0); done || lia. | ||
162 | + rewrite bool_decide_eq_false in H. apply eq_None_not_Some in H. | ||
163 | by simplify_option_eq. | ||
164 | - (* E_Rec *) | ||
165 | exists (S n). rewrite eval_S. by csimpl. | ||
166 | - (* E_Let *) | ||
167 | exists (S n). rewrite eval_S. by csimpl. | ||
168 | - (* E_With *) | ||
169 | exists (S n). rewrite eval_S. csimpl. | ||
170 | apply bind_Some. exists (V_Attrset bs). | ||
171 | by destruct n; try discriminate. | ||
172 | - (* E_WithNoAttrset *) | ||
173 | exists (S n). rewrite eval_S. csimpl. | ||
174 | apply bind_Some. exists v1. | ||
175 | destruct v1; try by destruct n; try discriminate. | ||
176 | exfalso. apply H. by exists bs. | ||
177 | - (* E_ApplySimple *) | ||
178 | exists (S n). rewrite eval_S. simpl. | ||
179 | apply bind_Some. exists (V_Fn x e1). | ||
180 | split; [|assumption]. | ||
181 | destruct n; try discriminate; reflexivity. | ||
182 | - (* E_ApplyAttrset *) | ||
183 | exists (S n). rewrite eval_S. csimpl. | ||
184 | apply bind_Some. exists (V_AttrsetFn m e0). | ||
185 | destruct n; try discriminate. split; [done|]. | ||
186 | apply bind_Some. exists (V_Attrset bs). split; [done|]. | ||
187 | apply bind_Some. exists bs. split; [done|]. | ||
188 | apply bind_Some. apply matches_complete in H. | ||
189 | by exists bs'. | ||
190 | - (* E_ApplyFunctor *) | ||
191 | exists (S n). rewrite eval_S. csimpl. | ||
192 | apply bind_Some. exists (V_Attrset (<["__functor" := e2]>bs)). | ||
193 | destruct n; try discriminate. split; [done|]. | ||
194 | rewrite lookup_insert. by simplify_option_eq. | ||
195 | - (* E_IfTrue *) | ||
196 | exists (S n). rewrite eval_S. csimpl. | ||
197 | apply bind_Some. exists true. | ||
198 | by destruct n; try discriminate. | ||
199 | - (* E_IfFalse *) | ||
200 | exists (S n). rewrite eval_S. csimpl. | ||
201 | apply bind_Some. exists false. | ||
202 | by destruct n; try discriminate. | ||
203 | - (* E_Op *) | ||
204 | exists (S n). rewrite eval_S. simpl. | ||
205 | apply bind_Some. exists v1. | ||
206 | destruct n; try discriminate. | ||
207 | split. | ||
208 | + apply eval_value. lia. | ||
209 | + apply bind_Some. exists v2. split. | ||
210 | * apply eval_value. lia. | ||
211 | * apply binop_eval_complete in H. | ||
212 | apply bind_Some. by exists u. | ||
213 | - (* E_OpHasAttrTrue *) | ||
214 | exists (S n). rewrite eval_S. csimpl. | ||
215 | apply bind_Some. exists (V_Attrset bs). | ||
216 | destruct n; try discriminate. rewrite eval_S in Heval. | ||
217 | simplify_option_eq. by rewrite bool_decide_eq_true_2. | ||
218 | - (* E_OpHasAttrFalse *) | ||
219 | exists (S n). rewrite eval_S. csimpl. | ||
220 | apply bind_Some. exists (V_Attrset bs). | ||
221 | destruct n; try discriminate. rewrite eval_S in Heval. | ||
222 | simplify_option_eq. rewrite eq_None_not_Some in H. | ||
223 | by rewrite bool_decide_eq_false_2. | ||
224 | - (* E_OpHasAttrNoAttrset *) | ||
225 | exists (S n). rewrite eval_S. csimpl. | ||
226 | destruct n; try discriminate. rewrite eval_S in Heval. | ||
227 | simplify_option_eq. | ||
228 | apply bind_Some. exists v. | ||
229 | split; [apply eval_value; lia|]. | ||
230 | case_match; try done. | ||
231 | exfalso. apply H. by exists bs. | ||
232 | - (* E_Assert *) | ||
233 | exists (S n). rewrite eval_S. csimpl. | ||
234 | apply bind_Some. exists true. | ||
235 | split; [by destruct n | done]. | ||
236 | Qed. | ||
237 | |||
238 | Lemma eval_step_ctx : ∀ e e' E uf_ext uf_int n v'', | ||
239 | is_ctx uf_ext uf_int E → | ||
240 | e -->base e' → | ||
241 | eval n uf_ext (E e') = Some v'' → | ||
242 | ∃ m, eval m uf_ext (E e) = Some v''. | ||
243 | Proof. | ||
244 | intros e e' E uf_in uf_out n v'' Hctx Hbstep. | ||
245 | revert v''. | ||
246 | induction Hctx. | ||
247 | - intros. by apply eval_base_step with (e' := e') (n := n). | ||
248 | - inv H; intros. | ||
249 | + destruct n as [|n]; try discriminate. | ||
250 | rewrite eval_S in H. simplify_option_eq. | ||
251 | destruct xs. simplify_option_eq. | ||
252 | apply eval_le with (m := S n) in Heqo; try lia. | ||
253 | apply IHHctx in Heqo as [m He]. | ||
254 | exists (S (n `max` m)). | ||
255 | rewrite eval_S. simplify_option_eq. | ||
256 | rewrite eval_le with (n := m) (v' := V_Attrset H1) by lia || done. | ||
257 | simplify_option_eq. | ||
258 | case_match; by rewrite eval_le with (n := n) (v' := v'') by lia || done. | ||
259 | + intros. | ||
260 | destruct n as [|n]; try discriminate. | ||
261 | rewrite eval_S in H. simplify_option_eq. | ||
262 | destruct xs. simplify_option_eq. | ||
263 | apply eval_le with (m := S n) in Heqo; try lia. | ||
264 | apply IHHctx in Heqo as [m He]. | ||
265 | exists (S (n `max` m)). | ||
266 | rewrite eval_S. simplify_option_eq. | ||
267 | setoid_rewrite eval_le with (n := m); try lia || done. | ||
268 | simplify_option_eq. repeat case_match; | ||
269 | apply eval_le with (n := n); lia || done. | ||
270 | + intros. | ||
271 | destruct n as [|n]; try discriminate. | ||
272 | rewrite eval_S in H. simplify_option_eq. | ||
273 | apply eval_le with (m := S n) in Heqo; try lia. | ||
274 | apply IHHctx in Heqo as [m He]. | ||
275 | exists (S (n `max` m)). | ||
276 | rewrite eval_S. simplify_option_eq. | ||
277 | setoid_rewrite eval_le with (n := m); try lia || done. | ||
278 | simplify_option_eq. repeat case_match; | ||
279 | apply eval_le with (n := n); lia || done. | ||
280 | + (* X_Apply *) | ||
281 | intros. | ||
282 | destruct n as [|n]; try discriminate. | ||
283 | rewrite eval_S in H. simplify_option_eq. | ||
284 | apply eval_le with (m := S n) in Heqo; try done || lia. | ||
285 | apply IHHctx in Heqo as [m He]. | ||
286 | exists (S (n `max` m)). | ||
287 | rewrite eval_S. simplify_option_eq. | ||
288 | destruct H0; try discriminate. | ||
289 | * setoid_rewrite eval_le with (n := m); try done || lia. | ||
290 | simplify_option_eq. | ||
291 | setoid_rewrite eval_le with (n := n); done || lia. | ||
292 | * setoid_rewrite eval_le with (n := m); try done || lia. | ||
293 | simplify_option_eq. | ||
294 | rewrite eval_le with (n := n) at 1; try done || lia. | ||
295 | simplify_option_eq. | ||
296 | setoid_rewrite eval_le with (n := n); done || lia. | ||
297 | * setoid_rewrite eval_le with (n := m); try done || lia. | ||
298 | simplify_option_eq. | ||
299 | setoid_rewrite eval_le with (n := n); done || lia. | ||
300 | + intros. | ||
301 | destruct n as [|n]; try discriminate. | ||
302 | rewrite eval_S in H. simplify_option_eq. | ||
303 | destruct n; try discriminate. rewrite eval_S in Heqo. | ||
304 | simplify_option_eq. | ||
305 | apply eval_le with (m := S (S n)) in Heqo; try lia. | ||
306 | apply IHHctx in Heqo as [o He]. | ||
307 | exists (S (S (n `max` o))). | ||
308 | rewrite eval_S. simplify_option_eq. | ||
309 | destruct o as [|o]; try discriminate. | ||
310 | setoid_rewrite eval_le with (n := S o) (v' := V_AttrsetFn m e1); | ||
311 | try done || lia. | ||
312 | simplify_option_eq. | ||
313 | rewrite eval_le with (n := S o) (v' := V_Attrset H1); | ||
314 | try by rewrite eval_S || lia. | ||
315 | simplify_option_eq. | ||
316 | rewrite eval_le with (n := S n) (v' := v''); done || lia. | ||
317 | + intros. | ||
318 | destruct n as [|n]; try discriminate. | ||
319 | rewrite eval_S in H. simplify_option_eq. | ||
320 | apply eval_le with (m := S n) in Heqo. 2: lia. | ||
321 | apply IHHctx in Heqo as [m He]. | ||
322 | exists (S (n `max` m)). | ||
323 | rewrite eval_S. simplify_option_eq. | ||
324 | rewrite eval_le with (n := m) (v' := H1) by lia || done. | ||
325 | setoid_rewrite eval_le with (n := n) (v' := v''); try lia || done. | ||
326 | + intros. | ||
327 | destruct n as [|n]; try discriminate. | ||
328 | rewrite eval_S in H. simplify_option_eq. | ||
329 | apply eval_le with (m := S n) in Heqo. 2: lia. | ||
330 | apply IHHctx in Heqo as [m He]. | ||
331 | exists (S (n `max` m)). | ||
332 | destruct H0; try discriminate. | ||
333 | rewrite eval_S. simplify_option_eq. | ||
334 | setoid_rewrite eval_le with (n := m) (v' := p); try lia || done. | ||
335 | simplify_option_eq. destruct p; try discriminate. | ||
336 | apply eval_le with (n := n); lia || done. | ||
337 | + intros. | ||
338 | destruct n as [|n]; try discriminate. | ||
339 | rewrite eval_S in H. simplify_option_eq. | ||
340 | apply eval_le with (m := S n) in Heqo. 2: lia. | ||
341 | apply IHHctx in Heqo as [m He]. | ||
342 | exists (S (n `max` m)). | ||
343 | rewrite eval_S. simplify_option_eq. | ||
344 | rewrite eval_le with (n := n) (v' := H1) by lia || done. | ||
345 | rewrite eval_le with (n := m) (v' := H0) by lia || done. | ||
346 | simplify_option_eq. | ||
347 | apply eval_le with (n := n); lia || done. | ||
348 | + intros. | ||
349 | destruct n as [|n]; try discriminate. | ||
350 | rewrite eval_S in H. simplify_option_eq. | ||
351 | apply eval_le with (m := S n) in Heqo0. 2: lia. | ||
352 | apply IHHctx in Heqo0 as [m He]. | ||
353 | exists (S (n `max` m)). | ||
354 | rewrite eval_S. simplify_option_eq. | ||
355 | rewrite eval_le with (n := m) (v' := H1) by lia || done. | ||
356 | rewrite eval_le with (n := n) (v' := H0) by lia || done. | ||
357 | simplify_option_eq. | ||
358 | apply eval_le with (n := n) (v' := v''); lia || done. | ||
359 | + (* IsCtxItem_OpHasAttrL *) | ||
360 | intros. | ||
361 | destruct n as [|n]; try discriminate. | ||
362 | rewrite eval_S in H. simplify_option_eq. | ||
363 | apply eval_le with (m := S n) in Heqo. 2: lia. | ||
364 | apply IHHctx in Heqo as [m He]. | ||
365 | exists (S (n `max` m)). | ||
366 | rewrite eval_S. simplify_option_eq. | ||
367 | by rewrite eval_le with (n := m) (v' := H0) by lia || done. | ||
368 | + intros. | ||
369 | destruct n as [|n]; try discriminate. | ||
370 | rewrite eval_S in H. simplify_option_eq. | ||
371 | apply eval_le with (m := S n) in H. 2: lia. | ||
372 | apply IHHctx in H as [m He]. | ||
373 | exists (S (n `max` m)). | ||
374 | rewrite eval_S; simplify_option_eq. | ||
375 | apply eval_le with (n := m) (v' := v''); lia || done. | ||
376 | + intros. simplify_option_eq. | ||
377 | destruct n as [|n]; try discriminate. | ||
378 | rewrite eval_S in H. simplify_option_eq. | ||
379 | apply map_mapM_Some_L in Heqo. | ||
380 | destruct (map_Forall2_destruct _ _ _ _ _ Heqo) | ||
381 | as [v' [m2' [Hkm2' HeqH0]]]. simplify_option_eq. | ||
382 | apply map_Forall2_insert_inv in Heqo as [Hinterp HForall2]; try done. | ||
383 | apply eval_le with (m := S n) in Hinterp; try lia. | ||
384 | apply IHHctx in Hinterp as [m Hinterp]. | ||
385 | exists (S (n `max` m)). | ||
386 | rewrite eval_S. simplify_option_eq. | ||
387 | apply bind_Some. exists (<[x := v']> m2'). split; try done. | ||
388 | apply map_mapM_Some_L. | ||
389 | apply map_Forall2_insert_weak. | ||
390 | * apply eval_le with (n := m); lia || done. | ||
391 | * apply map_Forall2_impl_L | ||
392 | with (R1 := λ x y, eval n true x = Some y); try done. | ||
393 | intros u v Hjuv. by apply eval_le with (n := n); try lia. | ||
394 | Qed. | ||
395 | |||
396 | Lemma eval_step e e' v'' n : | ||
397 | e --> e' → | ||
398 | eval n false e' = Some v'' → | ||
399 | ∃ m, eval m false e = Some v''. | ||
400 | Proof. | ||
401 | intros. inv H. | ||
402 | apply (eval_step_ctx e1 e2 E false uf_int n v'' H1 H2 H0). | ||
403 | Qed. | ||
404 | |||
405 | Theorem eval_complete e (v' : value) : | ||
406 | e -->* v' → ∃ n, eval n false e = Some v'. | ||
407 | Proof. | ||
408 | intros [steps Hsteps] % rtc_nsteps. revert e v' Hsteps. | ||
409 | induction steps; intros e e' Hsteps; inv Hsteps. | ||
410 | - exists 1. apply eval_value. lia. | ||
411 | - destruct (IHsteps y e') as [n Hn]; try done. | ||
412 | clear IHsteps. by apply eval_step with (e := e) in Hn. | ||
413 | Qed. | ||