1use vstd::prelude::*;
20
21verus! {
22
23pub open spec fn map_spec(position: int, start: int, old_end: int, new_end: int) -> int {
25 if position < start {
26 position
27 } else if position >= old_end {
28 new_end + (position - old_end)
29 } else {
30 start
31 }
32}
33
34pub fn map_position(position: usize, start: usize, old_end: usize, new_end: usize) -> (mapped: usize)
38 requires
39 start <= old_end,
40 position >= old_end ==> new_end + (position - old_end) <= usize::MAX,
41 ensures
42 mapped as int == map_spec(position as int, start as int, old_end as int, new_end as int),
43{
44 if position < start {
45 position
46 } else if position >= old_end {
47 new_end.saturating_add(position - old_end)
48 } else {
49 start
50 }
51}
52
53proof fn map_spec_monotone(a: int, b: int, start: int, old_end: int, new_end: int)
57 requires
58 start <= old_end,
59 start <= new_end,
60 a <= b,
61 ensures
62 map_spec(a, start, old_end, new_end) <= map_spec(b, start, old_end, new_end),
63{
64}
65
66proof fn map_spec_in_bounds(
68 position: int,
69 start: int,
70 old_end: int,
71 new_end: int,
72 old_len: int,
73 new_len: int,
74)
75 requires
76 0 <= start <= old_end <= old_len,
77 0 <= start <= new_end <= new_len,
78 0 <= position <= old_len,
79 new_len == old_len - (old_end - start) + (new_end - start),
80 ensures
81 0 <= map_spec(position, start, old_end, new_end) <= new_len,
82{
83}
84
85}
86
87verus! {
88
89pub open spec fn to_ints(edits: Seq<(usize, usize)>) -> Seq<(int, int)> {
91 edits.map_values(|pair: (usize, usize)| (pair.0 as int, pair.1 as int))
92}
93
94pub open spec fn batch_ok(edits: Seq<(int, int)>, len: int) -> bool {
96 forall|i: int| #![trigger edits[i]] 0 <= i < edits.len() ==> {
97 let (s, e) = edits[i];
98 &&& 0 <= s <= e <= len
99 &&& i + 1 < edits.len() ==> {
100 let (s2, _) = edits[i + 1];
101 &&& s < s2
102 &&& e <= s2
103 }
104 }
105}
106
107proof fn insert_preserves(
110 edits: Seq<(usize, usize)>,
111 pre: Seq<(usize, (usize, usize))>,
112 j: usize,
113 i: usize,
114 pair: (usize, usize),
115)
116 requires
117 j as int <= pre.len(),
118 pre.len() == i as int,
119 (i as int) < edits.len(),
120 pair == edits[i as int],
121 forall|k: int| #![trigger pre[k]] 0 <= k < pre.len() ==> {
122 &&& (pre[k].0 as int) < i as int
123 &&& pre[k].1 == edits[pre[k].0 as int]
124 },
125 forall|a: int, b: int| #![trigger pre[a], pre[b]]
126 0 <= a < b < pre.len() ==> pre[a].0 != pre[b].0,
127 forall|k: int| #![trigger pre[k]] 0 <= k < pre.len() - 1 ==>
128 pre[k].1.0 <= pre[k + 1].1.0,
129 j > 0 ==> pre[j as int - 1].1.0 as int <= pair.0 as int,
130 forall|p: int| #![trigger pre[p]] j as int <= p < pre.len() ==>
131 pre[p].1.0 as int > pair.0 as int,
132 ensures
133 ({
134 let post = pre.insert(j as int, (i, pair));
135 &&& post.len() == i as int + 1
136 &&& forall|k: int| #![trigger post[k]] 0 <= k < post.len() ==> {
137 &&& (post[k].0 as int) < i as int + 1
138 &&& post[k].1 == edits[post[k].0 as int]
139 }
140 &&& forall|a: int, b: int| #![trigger post[a], post[b]]
141 0 <= a < b < post.len() ==> post[a].0 != post[b].0
142 &&& forall|k: int| #![trigger post[k]] 0 <= k < post.len() - 1 ==>
143 post[k].1.0 <= post[k + 1].1.0
144 }),
145{
146 let post = pre.insert(j as int, (i, pair));
147 assert forall|k: int| #![trigger post[k]] 0 <= k < post.len() implies {
148 &&& (post[k].0 as int) < i as int + 1
149 &&& post[k].1 == edits[post[k].0 as int]
150 } by {
151 if k == j as int {
152 assert(post[k] == (i, pair));
153 } else if k < j as int {
154 assert(post[k] == pre[k]);
155 } else {
156 assert(post[k] == pre[k - 1]);
157 }
158 }
159 assert forall|a: int, b: int| #![trigger post[a], post[b]]
160 0 <= a < b < post.len() implies post[a].0 != post[b].0 by {
161 if a == j as int {
162 assert(post[b] == pre[b - 1]);
163 } else if b == j as int {
164 assert(post[a] == pre[a]);
165 } else {
166 assert(post[a] == if a < j as int { pre[a] } else { pre[a - 1] });
167 assert(post[b] == if b < j as int { pre[b] } else { pre[b - 1] });
168 }
169 }
170 assert forall|k: int| #![trigger post[k]] 0 <= k < post.len() - 1 implies
171 post[k].1.0 <= post[k + 1].1.0 by {
172 if k + 1 < j as int {
173 assert(post[k] == pre[k]);
174 assert(post[k + 1] == pre[k + 1]);
175 } else if k + 1 == j as int {
176 assert(post[k] == pre[k]);
177 assert(post[k + 1] == (i, pair));
178 } else if k == j as int {
180 assert(post[k] == (i, pair));
181 assert(post[k + 1] == pre[k]);
182 } else {
184 assert(post[k] == pre[k - 1]);
185 assert(post[k + 1] == pre[k]);
186 }
187 }
188}
189
190#[allow(clippy::ptr_arg, clippy::needless_range_loop)]
195fn sort_by_start(edits: &Vec<(usize, usize)>) -> (out: Vec<(usize, (usize, usize))>)
196 ensures
197 out@.len() == edits@.len(),
198 forall|k: int| #![trigger out@[k]] 0 <= k < out@.len() ==> {
200 &&& (out@[k].0 as int) < edits@.len()
201 &&& out@[k].1 == edits@[out@[k].0 as int]
202 },
203 forall|a: int, b: int| #![trigger out@[a], out@[b]]
205 0 <= a < b < out@.len() ==> out@[a].0 != out@[b].0,
206 forall|k: int| #![trigger out@[k]] 0 <= k < out@.len() - 1 ==>
208 out@[k].1.0 <= out@[k + 1].1.0,
209{
210 let mut out: Vec<(usize, (usize, usize))> = Vec::new();
211 for i in 0..edits.len()
212 invariant
213 i <= edits.len(),
214 out@.len() == i as int,
215 forall|k: int| #![trigger out@[k]] 0 <= k < out@.len() ==> {
216 &&& (out@[k].0 as int) < i as int
217 &&& out@[k].1 == edits@[out@[k].0 as int]
218 },
219 forall|a: int, b: int| #![trigger out@[a], out@[b]]
220 0 <= a < b < out@.len() ==> out@[a].0 != out@[b].0,
221 forall|k: int| #![trigger out@[k]] 0 <= k < out@.len() - 1 ==>
222 out@[k].1.0 <= out@[k + 1].1.0,
223 {
224 let pair = edits[i];
225 let s = pair.0;
226 let ghost pre = out@;
227 let mut j = out.len();
229 while j > 0 && out[j - 1].1.0 > s
230 invariant
231 j <= out.len(),
232 out@ == pre,
233 forall|p: int| #![trigger out@[p]] j <= p < out@.len() ==>
234 out@[p].1.0 > s as int,
235 decreases j,
236 {
237 j -= 1;
238 }
239 out.insert(j, (i, pair));
240 proof {
241 insert_preserves(edits@, pre, j, i, pair);
242 }
243 }
244 out
245}
246
247#[allow(clippy::result_unit_err, clippy::needless_range_loop)]
253pub fn check_batch(len: usize, edits: Vec<(usize, usize)>) -> (out: Result<Vec<(usize, usize)>, ()>)
254 ensures
255 out.is_ok() ==> batch_ok(to_ints(out.unwrap()@), len as int),
256 out.is_err() ==> {
257 ||| exists|i: int| #![trigger edits@[i]] 0 <= i < edits@.len() && {
258 let (s, e) = edits@[i]; !(0 <= s <= e <= len as int)
259 }
260 ||| exists|i: int, j: int| #![trigger edits@[i], edits@[j]]
261 0 <= i < edits@.len() && 0 <= j < edits@.len() && i != j && {
262 let (si, ei) = edits@[i]; let (sj, _ej) = edits@[j];
263 &&& si == sj || (si <= sj && ei > sj)
264 }
265 },
266{
267 let sorted = sort_by_start(&edits);
268 let n = sorted.len();
269 let mut i = 0usize;
270 while i < n
272 invariant
273 0 <= i <= n,
274 n == sorted@.len(),
275 forall|k: int| #![trigger sorted@[k]] 0 <= k < sorted@.len() ==> {
277 &&& (sorted@[k].0 as int) < edits@.len()
278 &&& sorted@[k].1 == edits@[sorted@[k].0 as int]
279 },
280 forall|a: int, b: int| #![trigger sorted@[a], sorted@[b]]
281 0 <= a < b < sorted@.len() ==> sorted@[a].0 != sorted@[b].0,
282 forall|k: int| #![trigger sorted@[k]] 0 <= k < sorted@.len() - 1 ==>
283 sorted@[k].1.0 <= sorted@[k + 1].1.0,
284 forall|k: int| #![trigger sorted@[k]] 0 <= k < i as int ==> {
285 let (sk, ek) = sorted@[k].1;
286 &&& 0 <= sk as int
287 &&& sk <= ek
288 &&& ek <= len
289 },
290 forall|k: int| #![trigger sorted@[k]] 0 <= k < i as int - 1 ==> {
291 let (sk, ek) = sorted@[k].1;
292 let (sk1, _ek1) = sorted@[k + 1].1;
293 &&& sk < sk1
294 &&& ek <= sk1
295 },
296 decreases n - i,
297 {
298 let (s, e) = sorted[i].1;
299 if !(s <= e && e <= len) {
300 proof {
301 let w = sorted@[i as int].0 as int;
302 assert(0 <= w < edits@.len());
303 assert(edits@[w] == (s, e));
304 assert(!(0 <= s as int && s <= e && e <= len));
305 assert(exists|i2: int| #![trigger edits@[i2]] 0 <= i2 < edits@.len() && {
306 let (s2, e2) = edits@[i2]; !(0 <= s2 <= e2 <= len as int)
307 });
308 }
309 return Err(());
310 }
311 if i > 0 {
312 let (sp, ep) = sorted[i - 1].1;
313 if sp == s || ep > s {
314 proof {
315 let a = sorted@[i as int - 1].0 as int;
316 let b = sorted@[i as int].0 as int;
317 assert(0 <= a < edits@.len());
318 assert(0 <= b < edits@.len());
319 assert(a != b);
320 assert(edits@[a] == (sp, ep));
321 assert(edits@[b] == (s, e));
322 assert(sp as int <= s as int);
324 assert(exists|i2: int, j2: int| #![trigger edits@[i2], edits@[j2]]
325 0 <= i2 < edits@.len() && 0 <= j2 < edits@.len() && i2 != j2 && {
326 let (si, ei) = edits@[i2]; let (sj, _ej) = edits@[j2];
327 &&& si == sj || (si <= sj && ei > sj)
328 });
329 }
330 return Err(());
331 }
332 }
333 i += 1;
334 }
335 let mut result: Vec<(usize, usize)> = Vec::new();
337 let mut k = 0usize;
338 while k < n
339 invariant
340 0 <= k <= n,
341 n == sorted@.len(),
342 result@.len() == k as int,
343 forall|p: int| #![trigger result@[p]] 0 <= p < k as int ==>
344 result@[p] == sorted@[p].1,
345 decreases n - k,
346 {
347 result.push(sorted[k].1);
348 k += 1;
349 }
350 proof {
351 let ri = to_ints(result@);
352 assert forall|p: int| #![trigger ri[p]] 0 <= p < ri.len() implies {
353 let (s, e) = ri[p];
354 &&& 0 <= s <= e <= len as int
355 &&& p + 1 < ri.len() ==> {
356 let (s2, _) = ri[p + 1];
357 &&& s < s2 &&& e <= s2
358 }
359 } by {
360 assert(result@[p] == sorted@[p].1);
361 if p + 1 < ri.len() {
362 assert(result@[p + 1] == sorted@[p + 1].1);
363 }
364 }
365 assert(batch_ok(ri, len as int));
366 }
367 Ok(result)
368}
369
370}
371
372verus! {
373
374#[verifier::opaque]
405pub open spec fn batch3_ok(edits: Seq<(int, int, int)>, len: int) -> bool {
406 forall|i: int| #![trigger edits[i]] 0 <= i < edits.len() ==> {
407 let (s, oe, ne) = edits[i];
408 &&& 0 <= s <= oe <= len
409 &&& s <= ne
410 &&& i + 1 < edits.len() ==> {
411 let (s2, _oe2, _ne2) = edits[i + 1];
412 &&& s < s2
413 &&& oe <= s2
414 }
415 }
416}
417
418#[verifier::opaque]
421pub open spec fn len_after(len0: int, edits: Seq<(int, int, int)>, t: int) -> int
422 decreases t,
423{
424 if t <= 0 || t > edits.len() {
425 len0
426 } else {
427 let (_s, oe, ne) = edits[edits.len() - t];
428 len_after(len0, edits, t - 1) + (ne - oe)
429 }
430}
431
432#[verifier::opaque]
436pub open spec fn batch_map_spec(pos: int, edits: Seq<(int, int, int)>, t: int) -> int
437 decreases t,
438{
439 if t <= 0 || t > edits.len() {
440 pos
441 } else {
442 let (s, oe, ne) = edits[edits.len() - t];
443 map_spec(batch_map_spec(pos, edits, t - 1), s, oe, ne)
444 }
445}
446
447#[verifier::opaque]
452pub open spec fn direct_map(pos: int, edits: Seq<(int, int, int)>, i: int, delta: int) -> int
453 decreases edits.len() - i,
454{
455 if i < 0 || i >= edits.len() {
456 pos + delta
457 } else {
458 let (s, oe, ne) = edits[i];
459 if pos < s {
460 pos + delta
461 } else if pos >= oe {
462 direct_map(pos, edits, i + 1, delta + (ne - oe))
463 } else {
464 s + delta
467 }
468 }
469}
470
471proof fn lemma_batch3_chain(edits: Seq<(int, int, int)>, len: int, i: int, j: int)
474 requires
475 batch3_ok(edits, len),
476 0 <= i < j < edits.len(),
477 ensures
478 edits[i].1 <= edits[j].0,
479 decreases j - i,
480{
481 reveal(batch3_ok);
482 if j - i > 1 {
483 lemma_batch3_chain(edits, len, i + 1, j);
484 assert(edits[i].0 < edits[i + 1].0 && edits[i].1 <= edits[i + 1].0);
485 assert(edits[i + 1].0 <= edits[i + 1].1);
486 }
487}
488
489proof fn lemma_direct_map_delta(
493 pos: int,
494 edits: Seq<(int, int, int)>,
495 i: int,
496 delta: int,
497 extra: int,
498)
499 requires
500 0 <= i <= edits.len(),
501 ensures
502 direct_map(pos, edits, i, delta + extra) == direct_map(pos, edits, i, delta) + extra,
503 decreases edits.len() - i,
504{
505 reveal(direct_map);
506 if i < edits.len() {
507 let (_s, oe, ne) = edits[i];
508 if pos >= oe && pos >= _s {
509 lemma_direct_map_delta(pos, edits, i + 1, delta + (ne - oe), extra);
510 assert(direct_map(pos, edits, i, delta + extra)
511 == direct_map(pos, edits, i + 1, delta + (ne - oe) + extra));
512 assert(direct_map(pos, edits, i, delta)
513 == direct_map(pos, edits, i + 1, delta + (ne - oe)));
514 }
515 }
516}
517
518proof fn lemma_direct_lower(
522 pos: int,
523 edits: Seq<(int, int, int)>,
524 len: int,
525 i: int,
526 bound: int,
527)
528 requires
529 batch3_ok(edits, len),
530 0 <= i <= edits.len(),
531 pos >= bound,
532 forall|j: int| #![trigger edits[j]] i <= j < edits.len() ==> edits[j].0 >= bound,
533 ensures
534 direct_map(pos, edits, i, 0) >= bound,
535 decreases edits.len() - i,
536{
537 reveal(batch3_ok);
538 reveal(direct_map);
539 if i < edits.len() {
540 let (s, oe, ne) = edits[i];
541 if pos >= oe && pos >= s {
542 assert forall|j: int| #![trigger edits[j]]
544 i + 1 <= j < edits.len() implies edits[j].0 >= oe by {
545 lemma_batch3_chain(edits, len, i, j);
546 }
547 lemma_direct_lower(pos, edits, len, i + 1, oe);
548 lemma_direct_map_delta(pos, edits, i + 1, 0, ne - oe);
549 assert(direct_map(pos, edits, i, 0)
550 == direct_map(pos, edits, i + 1, ne - oe));
551 }
553 }
554}
555
556proof fn lemma_len_after_covers(len0: int, edits: Seq<(int, int, int)>, t: int)
561 requires
562 batch3_ok(edits, len0),
563 0 <= t <= edits.len(),
564 ensures
565 t > 0 ==> len_after(len0, edits, t) >= edits[edits.len() - t].2,
566 forall|i: int| #![trigger edits[i]]
567 0 <= i < edits.len() - t ==> edits[i].1 <= len_after(len0, edits, t),
568 decreases t,
569{
570 reveal(batch3_ok);
571 reveal(len_after);
572 if t > 0 {
573 lemma_len_after_covers(len0, edits, t - 1);
574 let j = edits.len() - t;
575 let (sj, oej, nej) = edits[j];
576 assert(len_after(len0, edits, t) == len_after(len0, edits, t - 1) + (nej - oej));
578 assert(len_after(len0, edits, t) >= nej && nej >= sj);
579 assert forall|i: int| #![trigger edits[i]]
580 0 <= i < edits.len() - t implies edits[i].1 <= len_after(len0, edits, t) by {
581 lemma_batch3_chain(edits, len0, i, j);
582 }
584 }
585}
586
587pub proof fn batch_map_monotone(a: int, b: int, len0: int, edits: Seq<(int, int, int)>, t: int)
590 requires
591 batch3_ok(edits, len0),
592 0 <= t <= edits.len(),
593 a <= b,
594 ensures
595 batch_map_spec(a, edits, t) <= batch_map_spec(b, edits, t),
596 decreases t,
597{
598 reveal(batch3_ok);
599 reveal(batch_map_spec);
600 if t > 0 {
601 batch_map_monotone(a, b, len0, edits, t - 1);
602 let (s, oe, ne) = edits[edits.len() - t];
603 map_spec_monotone(batch_map_spec(a, edits, t - 1), batch_map_spec(b, edits, t - 1), s, oe, ne);
604 }
605}
606
607pub proof fn batch_map_in_bounds(pos: int, len0: int, edits: Seq<(int, int, int)>, t: int)
610 requires
611 batch3_ok(edits, len0),
612 0 <= t <= edits.len(),
613 0 <= pos <= len0,
614 ensures
615 0 <= batch_map_spec(pos, edits, t) <= len_after(len0, edits, t),
616 decreases t,
617{
618 reveal(batch3_ok);
619 reveal(batch_map_spec);
620 reveal(len_after);
621 if t > 0 {
622 batch_map_in_bounds(pos, len0, edits, t - 1);
623 lemma_len_after_covers(len0, edits, t - 1);
624 let j = edits.len() - t;
625 let (s, oe, ne) = edits[j];
626 assert(len_after(len0, edits, t)
627 == len_after(len0, edits, t - 1) - (oe - s) + (ne - s));
628 map_spec_in_bounds(
629 batch_map_spec(pos, edits, t - 1),
630 s,
631 oe,
632 ne,
633 len_after(len0, edits, t - 1),
634 len_after(len0, edits, t),
635 );
636 }
637}
638
639proof fn lemma_direct_step(pos: int, edits: Seq<(int, int, int)>, len0: int, i: int)
644 requires
645 batch3_ok(edits, len0),
646 0 <= i < edits.len(),
647 0 <= pos <= len0,
648 ensures
649 direct_map(pos, edits, i, 0) == map_spec(
650 direct_map(pos, edits, i + 1, 0),
651 edits[i].0,
652 edits[i].1,
653 edits[i].2,
654 ),
655{
656 let (s, oe, ne) = edits[i];
657 let rest = direct_map(pos, edits, i + 1, 0);
658 reveal(batch3_ok);
659 reveal(direct_map);
660 if pos < s {
661 if i + 1 < edits.len() {
664 assert(pos < edits[i + 1].0);
665 }
666 assert(rest == pos);
667 } else if pos >= oe {
668 assert forall|j: int| #![trigger edits[j]]
671 i + 1 <= j < edits.len() implies edits[j].0 >= oe by {
672 lemma_batch3_chain(edits, len0, i, j);
673 }
674 lemma_direct_lower(pos, edits, len0, i + 1, oe);
675 lemma_direct_map_delta(pos, edits, i + 1, 0, ne - oe);
676 assert(direct_map(pos, edits, i, 0) == direct_map(pos, edits, i + 1, ne - oe));
677 assert(rest >= oe);
678 } else {
679 if i + 1 < edits.len() {
683 assert(pos < edits[i + 1].0);
684 }
685 assert(rest == pos);
686 }
687}
688
689proof fn lemma_batch_compose_step(pos: int, len0: int, edits: Seq<(int, int, int)>, t: int)
691 requires
692 batch3_ok(edits, len0),
693 0 <= t <= edits.len(),
694 0 <= pos <= len0,
695 ensures
696 batch_map_spec(pos, edits, t) == direct_map(pos, edits, edits.len() - t, 0),
697 decreases t,
698{
699 reveal(batch_map_spec);
700 reveal(direct_map);
701 if t > 0 {
702 lemma_batch_compose_step(pos, len0, edits, t - 1);
703 lemma_direct_step(pos, edits, len0, edits.len() - t);
704 assert(batch_map_spec(pos, edits, t)
709 == map_spec(direct_map(pos, edits, edits.len() - t + 1, 0),
710 edits[edits.len() - t].0, edits[edits.len() - t].1, edits[edits.len() - t].2));
711 }
712}
713
714pub proof fn batch_map_composition(pos: int, len0: int, edits: Seq<(int, int, int)>)
720 requires
721 batch3_ok(edits, len0),
722 0 <= pos <= len0,
723 ensures
724 batch_map_spec(pos, edits, edits.len() as int) == direct_map(pos, edits, 0, 0),
725{
726 lemma_batch_compose_step(pos, len0, edits, edits.len() as int);
727}
728
729}