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 r1.loc() == old(r1).loc(),
102 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 r.loc() == old(r).loc(),
118 other.loc() == old(r).loc(),
119 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 r.loc() == old(r).loc(),
136 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 r1.loc() == old(r1).loc(),
157 r2.loc() == old(r1).loc(),
158 r1.value() == v1,
159 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 r1.loc() == old(r1).loc(),
184 r2.loc() == old(r1).loc(),
185 r1.value() == v1,
186 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| #![trigger m.dom().contains(i)] 0 <= i < values.len() ==> !m.dom().contains(i),
220 all.loc() == loc,
221 all.value() == combine_values::<P>(values.skip(offset)),
222 decreases values.len() - offset,
223{
224 assert(m.dom().contains(offset));
225 assert(m[offset].loc() == loc && m[offset].value() == values[offset]);
226 let tracked p = m.tracked_remove(offset);
227 if offset == values.len() - 1 {
228 assert(combine_values::<P>(values.skip(offset)) == values[offset]) by {
229 lemma_pcm_properties::<P>(); reveal_with_fuel(combine_values, 2);
231 };
232 p
233 } else {
234 assert(combine_values::<P>(values.skip(offset)) == P::op(
235 values[offset],
236 combine_values::<P>(values.skip(offset + 1)),
237 )) by {
238 assert(values[offset] == values.skip(offset)[0]);
239 assert(values.skip(offset + 1) == values.skip(offset).skip(1));
240 }
241 assert forall|i|
242 #![trigger m.dom().contains(i)]
243 offset + 1 <= i < values.len() implies m.dom().contains(i) && m[i].loc() == loc
244 && m[i].value() == values[i] by {
245 assert(m.dom().contains(i));
246 assert(m[i].loc() == loc && m[i].value() == values[i]);
247 }
248 let tracked most = aggregate_resources_from_map_starting_at_offset(
249 m,
250 loc,
251 values,
252 offset + 1,
253 );
254 assert(most.loc() == loc);
255 assert(most.value() == combine_values::<P>(values.skip(offset + 1)));
256 p.join(most)
257 }
258}
259
260proof fn store_resources_into_map_starting_at_offset<P: PCM>(
269 tracked m: &mut Map<int, Resource<P>>,
270 values: Seq<P>,
271 offset: int,
272 tracked p: Resource<P>,
273)
274 requires
275 0 <= offset < values.len(),
276 forall|i| #![trigger old(m).dom().contains(i)] 0 <= i < offset ==> old(m).dom().contains(i),
277 forall|i|
278 #![trigger old(m)[i]]
279 0 <= i < offset ==> old(m)[i].loc() == p.loc() && old(m)[i].value() == values[i],
280 forall|i|
281 #![trigger old(m).dom().contains(i)]
282 offset <= i < values.len() ==> !old(m).dom().contains(i),
283 p.value() == combine_values::<P>(values.skip(offset)),
284 ensures
285 forall|i| #![trigger m.dom().contains(i)] 0 <= i < values.len() ==> m.dom().contains(i),
286 forall|i|
287 #![trigger m[i]]
288 0 <= i < values.len() ==> m[i].loc() == p.loc() && m[i].value() == values[i],
289 decreases values.len() - offset,
290{
291 assert(combine_values::<P>(values.skip(offset)) == P::op(
292 values[offset],
293 combine_values::<P>(values.skip(offset + 1)),
294 )) by {
295 assert(values[offset] == values.skip(offset)[0]);
296 assert(values.skip(offset + 1) == values.skip(offset).skip(1));
297 }
298 let tracked (p_first, p_rest) = p.split(
299 values[offset],
300 combine_values::<P>(values.skip(offset + 1)),
301 );
302 m.tracked_insert(offset, p_first);
303 if offset < values.len() - 1 {
304 store_resources_into_map_starting_at_offset(m, values, offset + 1, p_rest);
305 }
306}
307
308pub proof fn validate_multiple<P: PCM>(
326 tracked m: &mut Map<int, Resource<P>>,
327 values: Seq<P>,
328 tracked shared: &Resource<P>,
329)
330 requires
331 values.len() > 0,
332 forall|i|
333 #![trigger old(m).dom().contains(i)]
334 0 <= i < values.len() ==> old(m).dom().contains(i),
335 forall|i|
336 #![trigger old(m)[i]]
337 0 <= i < values.len() ==> old(m)[i].loc() == shared.loc() && old(m)[i].value()
338 == values[i],
339 ensures
340 forall|i| #![trigger m.dom().contains(i)] 0 <= i < values.len() ==> m.dom().contains(i),
341 forall|i|
342 #![trigger m[i]]
343 0 <= i < values.len() ==> m[i].loc() == shared.loc() && m[i].value() == values[i],
344 P::op(combine_values::<P>(values), shared.value()).valid(),
345{
346 let tracked mut agg = aggregate_resources_from_map_starting_at_offset(
347 m,
348 shared.loc(),
349 values,
350 0,
351 );
352 assert(agg.value() == combine_values::<P>(values)) by {
353 assert(values == values.skip(0));
354 }
355 agg.validate_2(shared);
356 store_resources_into_map_starting_at_offset(m, values, 0, agg);
357}
358
359pub proof fn validate_3<P: PCM>(
363 tracked r1: &mut Resource<P>,
364 tracked r2: &mut Resource<P>,
365 tracked r3: &Resource<P>,
366)
367 requires
368 old(r1).loc() == r3.loc(),
369 old(r2).loc() == r3.loc(),
370 ensures
371 r1.loc() == r3.loc(),
372 r2.loc() == r3.loc(),
373 r1.value() == old(r1).value(),
374 r2.value() == old(r2).value(),
375 P::op(r1.value(), P::op(r2.value(), r3.value())).valid(),
376{
377 lemma_pcm_properties::<P>();
378 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
379 let values: Seq<P> = seq![r1.value(), r2.value()];
380 m.tracked_insert(0, r1.extract());
381 m.tracked_insert(1, r2.extract());
382 assert(combine_values::<P>(values) == P::op(old(r1).value(), old(r2).value())) by {
383 lemma_pcm_properties::<P>();
384 reveal_with_fuel(combine_values, 3);
385 }
386 validate_multiple(&mut m, values, r3);
387 let tracked mut new_r1 = m.tracked_remove(0);
388 let tracked mut new_r2 = m.tracked_remove(1);
389 tracked_swap(r1, &mut new_r1);
390 tracked_swap(r2, &mut new_r2);
391 assert(P::op(r1.value(), P::op(r2.value(), r3.value())).valid()) by {
392 lemma_pcm_associative::<P>();
393 };
394}
395
396pub proof fn validate_4<P: PCM>(
400 tracked r1: &mut Resource<P>,
401 tracked r2: &mut Resource<P>,
402 tracked r3: &mut Resource<P>,
403 tracked r4: &Resource<P>,
404)
405 requires
406 old(r1).loc() == r4.loc(),
407 old(r2).loc() == r4.loc(),
408 old(r3).loc() == r4.loc(),
409 ensures
410 r1.loc() == r4.loc(),
411 r2.loc() == r4.loc(),
412 r3.loc() == r4.loc(),
413 r1.value() == old(r1).value(),
414 r2.value() == old(r2).value(),
415 r3.value() == old(r3).value(),
416 P::op(r1.value(), P::op(r2.value(), P::op(r3.value(), r4.value()))).valid(),
417{
418 lemma_pcm_properties::<P>();
419 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
420 let values: Seq<P> = seq![r1.value(), r2.value(), r3.value()];
421 m.tracked_insert(0, r1.extract());
422 m.tracked_insert(1, r2.extract());
423 m.tracked_insert(2, r3.extract());
424 assert(combine_values::<P>(values) == P::op(
425 old(r1).value(),
426 P::op(old(r2).value(), old(r3).value()),
427 )) by {
428 lemma_pcm_properties::<P>();
429 reveal_with_fuel(combine_values, 4);
430 }
431 validate_multiple(&mut m, values, r4);
432 let tracked mut new_r1 = m.tracked_remove(0);
433 let tracked mut new_r2 = m.tracked_remove(1);
434 let tracked mut new_r3 = m.tracked_remove(2);
435 tracked_swap(r1, &mut new_r1);
436 tracked_swap(r2, &mut new_r2);
437 tracked_swap(r3, &mut new_r3);
438 assert(P::op(r1.value(), P::op(r2.value(), P::op(r3.value(), r4.value()))).valid()) by {
439 lemma_pcm_associative::<P>();
440 }
441}
442
443pub proof fn validate_5<P: PCM>(
447 tracked r1: &mut Resource<P>,
448 tracked r2: &mut Resource<P>,
449 tracked r3: &mut Resource<P>,
450 tracked r4: &mut Resource<P>,
451 tracked r5: &Resource<P>,
452)
453 requires
454 old(r1).loc() == r5.loc(),
455 old(r2).loc() == r5.loc(),
456 old(r3).loc() == r5.loc(),
457 old(r4).loc() == r5.loc(),
458 ensures
459 r1.loc() == r5.loc(),
460 r2.loc() == r5.loc(),
461 r3.loc() == r5.loc(),
462 r4.loc() == r5.loc(),
463 r1.value() == old(r1).value(),
464 r2.value() == old(r2).value(),
465 r3.value() == old(r3).value(),
466 r4.value() == old(r4).value(),
467 P::op(
468 r1.value(),
469 P::op(r2.value(), P::op(r3.value(), P::op(r4.value(), r5.value()))),
470 ).valid(),
471{
472 lemma_pcm_properties::<P>();
473 let tracked mut m: Map<int, Resource<P>> = Map::<int, Resource<P>>::tracked_empty();
474 let values: Seq<P> = seq![r1.value(), r2.value(), r3.value(), r4.value()];
475 assert(combine_values::<P>(values) == P::op(
476 old(r1).value(),
477 P::op(old(r2).value(), P::op(old(r3).value(), old(r4).value())),
478 )) by {
479 lemma_pcm_properties::<P>();
480 reveal_with_fuel(combine_values, 5);
481 }
482 m.tracked_insert(0, r1.extract());
483 m.tracked_insert(1, r2.extract());
484 m.tracked_insert(2, r3.extract());
485 m.tracked_insert(3, r4.extract());
486 validate_multiple(&mut m, values, r5);
487 let tracked mut new_r1 = m.tracked_remove(0);
488 let tracked mut new_r2 = m.tracked_remove(1);
489 let tracked mut new_r3 = m.tracked_remove(2);
490 let tracked mut new_r4 = m.tracked_remove(3);
491 tracked_swap(r1, &mut new_r1);
492 tracked_swap(r2, &mut new_r2);
493 tracked_swap(r3, &mut new_r3);
494 tracked_swap(r4, &mut new_r4);
495 assert(P::op(
496 r1.value(),
497 P::op(r2.value(), P::op(r3.value(), P::op(r4.value(), r5.value()))),
498 ).valid()) by {
499 lemma_pcm_associative::<P>();
500 }
501}
502
503}