1use super::super::map::*;
2use super::super::modes::*;
3use super::super::prelude::*;
4use super::super::seq::*;
5use super::Loc;
6use super::pcm::Resource;
7use super::pcm::*;
8use super::relations::*;
9
10verus! {
11
12broadcast use super::super::group_vstd_default;
13
14pub open spec fn combine_values<P: PCM>(values: Seq<P>) -> P
16 decreases values.len(),
17{
18 if values.len() == 0 {
19 P::unit()
20 } else {
21 P::op(values[0], combine_values(values.skip(1)))
22 }
23}
24
25pub proof fn lemma_pcm_properties<P: PCM>()
32 ensures
33 forall|a: P, b: P| (#[trigger] P::op(a, b)).valid() ==> a.valid(),
34 forall|a: P, b: P| (#[trigger] P::op(a, b)) == P::op(b, a),
35 forall|a: P| (#[trigger] P::op(a, P::unit())) == a,
36 P::valid(P::unit()),
37{
38 assert forall|a: P, b: P| (#[trigger] P::op(a, b)).valid() implies a.valid() by {
39 P::valid_op(a, b);
40 }
41 assert forall|a: P, b: P| (#[trigger] P::op(a, b)) == P::op(b, a) by {
42 P::commutative(a, b);
43 }
44 assert forall|a: P| P::op(a, P::unit()) == a by {
45 P::op_unit(a);
46 }
47 assert(P::valid(P::unit())) by {
48 P::unit_valid();
49 }
50}
51
52pub proof fn lemma_pcm_associative<P: PCM>()
58 ensures
59 forall|a: P, b: P, c: P| (#[trigger] P::op(a, P::op(b, c))) == P::op(P::op(a, b), c),
60{
61 assert forall|a: P, b: P, c: P| (#[trigger] P::op(a, P::op(b, c))) == P::op(P::op(a, b), c) by {
62 P::associative(a, b, c);
63 }
64}
65
66pub proof fn copy_duplicable_part<P: PCM>(tracked r: &Resource<P>, new_value: P) -> (tracked out:
71 Resource<P>)
72 requires
73 r.value() == P::op(r.value(), new_value),
74 ensures
75 out.loc() == r.loc(),
76 out.value() == new_value,
77{
78 lemma_pcm_properties::<P>();
79 r.validate();
80 r.duplicate_previous(new_value)
81}
82
83pub proof fn duplicate<P: PCM>(tracked r: &Resource<P>) -> (tracked other: Resource<P>)
87 requires
88 P::op(r.value(), r.value()) == r.value(),
89 ensures
90 other.loc() == r.loc(),
91 other.value() == r.value(),
92{
93 copy_duplicable_part(r, r.value())
94}
95
96pub proof fn incorporate<P: PCM>(tracked r1: &mut Resource<P>, tracked r2: Resource<P>)
98 requires
99 old(r1).loc() == r2.loc(),
100 ensures
101 final(r1).loc() == old(r1).loc(),
102 final(r1).value() == P::op(old(r1).value(), r2.value()),
103{
104 let tracked mut r = r1.extract();
105 let tracked mut joined_r = r.join(r2);
106 tracked_swap(r1, &mut joined_r);
107}
108
109pub proof fn split_mut<P: PCM>(tracked r: &mut Resource<P>, left: P, right: P) -> (tracked other:
113 Resource<P>)
114 requires
115 old(r).value() == P::op(left, right),
116 ensures
117 final(r).loc() == old(r).loc(),
118 other.loc() == old(r).loc(),
119 final(r).value() == left,
120 other.value() == right,
121{
122 let tracked mut r_value = r.extract();
123 let tracked (mut r_left, r_right) = r_value.split(left, right);
124 tracked_swap(r, &mut r_left);
125 r_right
126}
127
128pub proof fn update_mut<P: PCM>(tracked r: &mut Resource<P>, new_value: P)
132 requires
133 frame_preserving_update(old(r).value(), new_value),
134 ensures
135 final(r).loc() == old(r).loc(),
136 final(r).value() == new_value,
137{
138 let tracked mut r_value = r.extract();
139 let tracked mut r_upd = r_value.update(new_value);
140 tracked_swap(r, &mut r_upd);
141}
142
143pub proof fn redistribute<P: PCM>(
147 tracked r1: &mut Resource<P>,
148 tracked r2: &mut Resource<P>,
149 v1: P,
150 v2: P,
151)
152 requires
153 old(r1).loc() == old(r2).loc(),
154 P::op(old(r1).value(), old(r2).value()) == P::op(v1, v2),
155 ensures
156 final(r1).loc() == old(r1).loc(),
157 final(r2).loc() == old(r1).loc(),
158 final(r1).value() == v1,
159 final(r2).value() == v2,
160{
161 lemma_pcm_properties::<P>();
162 let tracked r2_extracted = r2.extract();
163 incorporate(r1, r2_extracted);
164 let tracked mut r2_new = split_mut(r1, v1, v2);
165 tracked_swap(r2, &mut r2_new);
166}
167
168pub proof fn update_and_redistribute<P: PCM>(
174 tracked r1: &mut Resource<P>,
175 tracked r2: &mut Resource<P>,
176 v1: P,
177 v2: P,
178)
179 requires
180 old(r1).loc() == old(r2).loc(),
181 frame_preserving_update(P::op(old(r1).value(), old(r2).value()), P::op(v1, v2)),
182 ensures
183 final(r1).loc() == old(r1).loc(),
184 final(r2).loc() == old(r1).loc(),
185 final(r1).value() == v1,
186 final(r2).value() == v2,
187{
188 lemma_pcm_properties::<P>();
189 let tracked r2_extracted = r2.extract();
190 incorporate(r1, r2_extracted);
191 update_mut(r1, P::op(v1, v2));
192 let tracked mut r2_new = split_mut(r1, v1, v2);
193 tracked_swap(r2, &mut r2_new);
194}
195
196proof fn aggregate_resources_from_map_starting_at_offset<P: PCM>(
202 tracked m: &mut Map<int, Resource<P>>,
203 loc: Loc,
204 values: Seq<P>,
205 offset: int,
206) -> (tracked all: Resource<P>)
207 requires
208 0 <= offset < values.len(),
209 forall|i|
210 #![trigger old(m).dom().contains(i)]
211 0 <= i < offset ==> !old(m).dom().contains(i),
212 forall|i|
213 #![trigger old(m).dom().contains(i)]
214 offset <= i < values.len() ==> old(m).dom().contains(i),
215 forall|i|
216 #![trigger old(m)[i]]
217 offset <= i < values.len() ==> old(m)[i].loc() == loc && old(m)[i].value() == values[i],
218 ensures
219 forall|i|
220 #![trigger final(m).dom().contains(i)]
221 0 <= i < values.len() ==> !final(m).dom().contains(i),
222 all.loc() == loc,
223 all.value() == combine_values::<P>(values.skip(offset)),
224 decreases values.len() - offset,
225{
226 assert(m.dom().contains(offset));
227 assert(m[offset].loc() == loc && m[offset].value() == values[offset]);
228 let tracked p = m.tracked_remove(offset);
229 if offset == values.len() - 1 {
230 assert(combine_values::<P>(values.skip(offset)) == values[offset]) by {
231 lemma_pcm_properties::<P>(); reveal_with_fuel(combine_values, 2);
233 };
234 p
235 } else {
236 assert(combine_values::<P>(values.skip(offset)) == P::op(
237 values[offset],
238 combine_values::<P>(values.skip(offset + 1)),
239 )) by {
240 assert(values[offset] == values.skip(offset)[0]);
241 assert(values.skip(offset + 1) == values.skip(offset).skip(1));
242 }
243 assert forall|i|
244 #![trigger m.dom().contains(i)]
245 offset + 1 <= i < values.len() implies m.dom().contains(i) && m[i].loc() == loc
246 && m[i].value() == values[i] by {
247 assert(m.dom().contains(i));
248 assert(m[i].loc() == loc && m[i].value() == values[i]);
249 }
250 let tracked most = aggregate_resources_from_map_starting_at_offset(
251 m,
252 loc,
253 values,
254 offset + 1,
255 );
256 assert(most.loc() == loc);
257 assert(most.value() == combine_values::<P>(values.skip(offset + 1)));
258 p.join(most)
259 }
260}
261
262proof fn store_resources_into_map_starting_at_offset<P: PCM>(
271 tracked m: &mut Map<int, Resource<P>>,
272 values: Seq<P>,
273 offset: int,
274 tracked p: Resource<P>,
275)
276 requires
277 0 <= offset < values.len(),
278 forall|i| #![trigger old(m).dom().contains(i)] 0 <= i < offset ==> old(m).dom().contains(i),
279 forall|i|
280 #![trigger old(m)[i]]
281 0 <= i < offset ==> old(m)[i].loc() == p.loc() && old(m)[i].value() == values[i],
282 forall|i|
283 #![trigger old(m).dom().contains(i)]
284 offset <= i < values.len() ==> !old(m).dom().contains(i),
285 p.value() == combine_values::<P>(values.skip(offset)),
286 ensures
287 forall|i|
288 #![trigger final(m).dom().contains(i)]
289 0 <= i < values.len() ==> final(m).dom().contains(i),
290 forall|i|
291 #![trigger final(m)[i]]
292 0 <= i < values.len() ==> final(m)[i].loc() == p.loc() && final(m)[i].value()
293 == values[i],
294 decreases values.len() - offset,
295{
296 assert(combine_values::<P>(values.skip(offset)) == P::op(
297 values[offset],
298 combine_values::<P>(values.skip(offset + 1)),
299 )) by {
300 assert(values[offset] == values.skip(offset)[0]);
301 assert(values.skip(offset + 1) == values.skip(offset).skip(1));
302 }
303 let tracked (p_first, p_rest) = p.split(
304 values[offset],
305 combine_values::<P>(values.skip(offset + 1)),
306 );
307 m.tracked_insert(offset, p_first);
308 if offset < values.len() - 1 {
309 store_resources_into_map_starting_at_offset(m, values, offset + 1, p_rest);
310 }
311}
312
313pub proof fn validate_multiple<P: PCM>(
331 tracked m: &mut Map<int, Resource<P>>,
332 values: Seq<P>,
333 tracked shared: &Resource<P>,
334)
335 requires
336 values.len() > 0,
337 forall|i|
338 #![trigger old(m).dom().contains(i)]
339 0 <= i < values.len() ==> old(m).dom().contains(i),
340 forall|i|
341 #![trigger old(m)[i]]
342 0 <= i < values.len() ==> old(m)[i].loc() == shared.loc() && old(m)[i].value()
343 == values[i],
344 ensures
345 forall|i|
346 #![trigger final(m).dom().contains(i)]
347 0 <= i < values.len() ==> final(m).dom().contains(i),
348 forall|i|
349 #![trigger final(m)[i]]
350 0 <= i < values.len() ==> final(m)[i].loc() == shared.loc() && final(m)[i].value()
351 == values[i],
352 P::op(combine_values::<P>(values), shared.value()).valid(),
353{
354 let tracked mut agg = aggregate_resources_from_map_starting_at_offset(
355 m,
356 shared.loc(),
357 values,
358 0,
359 );
360 assert(agg.value() == combine_values::<P>(values)) by {
361 assert(values == values.skip(0));
362 }
363 agg.validate_2(shared);
364 store_resources_into_map_starting_at_offset(m, values, 0, agg);
365}
366
367pub proof fn validate_3<P: PCM>(
371 tracked r1: &mut Resource<P>,
372 tracked r2: &mut Resource<P>,
373 tracked r3: &Resource<P>,
374)
375 requires
376 old(r1).loc() == r3.loc(),
377 old(r2).loc() == r3.loc(),
378 ensures
379 final(r1).loc() == r3.loc(),
380 final(r2).loc() == r3.loc(),
381 final(r1).value() == old(r1).value(),
382 final(r2).value() == old(r2).value(),
383 P::op(final(r1).value(), P::op(final(r2).value(), r3.value())).valid(),
384{
385 lemma_pcm_properties::<P>();
386 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
387 let values: Seq<P> = seq![r1.value(), r2.value()];
388 m.tracked_insert(0, r1.extract());
389 m.tracked_insert(1, r2.extract());
390 assert(combine_values::<P>(values) == P::op(old(r1).value(), old(r2).value())) by {
391 lemma_pcm_properties::<P>();
392 reveal_with_fuel(combine_values, 3);
393 }
394 validate_multiple(&mut m, values, r3);
395 let tracked mut new_r1 = m.tracked_remove(0);
396 let tracked mut new_r2 = m.tracked_remove(1);
397 tracked_swap(r1, &mut new_r1);
398 tracked_swap(r2, &mut new_r2);
399 assert(P::op(r1.value(), P::op(r2.value(), r3.value())).valid()) by {
400 lemma_pcm_associative::<P>();
401 };
402}
403
404pub proof fn validate_4<P: PCM>(
408 tracked r1: &mut Resource<P>,
409 tracked r2: &mut Resource<P>,
410 tracked r3: &mut Resource<P>,
411 tracked r4: &Resource<P>,
412)
413 requires
414 old(r1).loc() == r4.loc(),
415 old(r2).loc() == r4.loc(),
416 old(r3).loc() == r4.loc(),
417 ensures
418 final(r1).loc() == r4.loc(),
419 final(r2).loc() == r4.loc(),
420 final(r3).loc() == r4.loc(),
421 final(r1).value() == old(r1).value(),
422 final(r2).value() == old(r2).value(),
423 final(r3).value() == old(r3).value(),
424 P::op(
425 final(r1).value(),
426 P::op(final(r2).value(), P::op(final(r3).value(), r4.value())),
427 ).valid(),
428{
429 lemma_pcm_properties::<P>();
430 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
431 let values: Seq<P> = seq![r1.value(), r2.value(), r3.value()];
432 m.tracked_insert(0, r1.extract());
433 m.tracked_insert(1, r2.extract());
434 m.tracked_insert(2, r3.extract());
435 assert(combine_values::<P>(values) == P::op(
436 old(r1).value(),
437 P::op(old(r2).value(), old(r3).value()),
438 )) by {
439 lemma_pcm_properties::<P>();
440 reveal_with_fuel(combine_values, 4);
441 }
442 validate_multiple(&mut m, values, r4);
443 let tracked mut new_r1 = m.tracked_remove(0);
444 let tracked mut new_r2 = m.tracked_remove(1);
445 let tracked mut new_r3 = m.tracked_remove(2);
446 tracked_swap(r1, &mut new_r1);
447 tracked_swap(r2, &mut new_r2);
448 tracked_swap(r3, &mut new_r3);
449 assert(P::op(r1.value(), P::op(r2.value(), P::op(r3.value(), r4.value()))).valid()) by {
450 lemma_pcm_associative::<P>();
451 }
452}
453
454pub proof fn validate_5<P: PCM>(
458 tracked r1: &mut Resource<P>,
459 tracked r2: &mut Resource<P>,
460 tracked r3: &mut Resource<P>,
461 tracked r4: &mut Resource<P>,
462 tracked r5: &Resource<P>,
463)
464 requires
465 old(r1).loc() == r5.loc(),
466 old(r2).loc() == r5.loc(),
467 old(r3).loc() == r5.loc(),
468 old(r4).loc() == r5.loc(),
469 ensures
470 final(r1).loc() == r5.loc(),
471 final(r2).loc() == r5.loc(),
472 final(r3).loc() == r5.loc(),
473 final(r4).loc() == r5.loc(),
474 final(r1).value() == old(r1).value(),
475 final(r2).value() == old(r2).value(),
476 final(r3).value() == old(r3).value(),
477 final(r4).value() == old(r4).value(),
478 P::op(
479 final(r1).value(),
480 P::op(
481 final(r2).value(),
482 P::op(final(r3).value(), P::op(final(r4).value(), r5.value())),
483 ),
484 ).valid(),
485{
486 lemma_pcm_properties::<P>();
487 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
488 let values: Seq<P> = seq![r1.value(), r2.value(), r3.value(), r4.value()];
489 assert(combine_values::<P>(values) == P::op(
490 old(r1).value(),
491 P::op(old(r2).value(), P::op(old(r3).value(), old(r4).value())),
492 )) by {
493 lemma_pcm_properties::<P>();
494 reveal_with_fuel(combine_values, 5);
495 }
496 m.tracked_insert(0, r1.extract());
497 m.tracked_insert(1, r2.extract());
498 m.tracked_insert(2, r3.extract());
499 m.tracked_insert(3, r4.extract());
500 validate_multiple(&mut m, values, r5);
501 let tracked mut new_r1 = m.tracked_remove(0);
502 let tracked mut new_r2 = m.tracked_remove(1);
503 let tracked mut new_r3 = m.tracked_remove(2);
504 let tracked mut new_r4 = m.tracked_remove(3);
505 tracked_swap(r1, &mut new_r1);
506 tracked_swap(r2, &mut new_r2);
507 tracked_swap(r3, &mut new_r3);
508 tracked_swap(r4, &mut new_r4);
509 assert(P::op(
510 r1.value(),
511 P::op(r2.value(), P::op(r3.value(), P::op(r4.value(), r5.value()))),
512 ).valid()) by {
513 lemma_pcm_associative::<P>();
514 }
515}
516
517}