1use vstd::prelude::*;
9
10use crate::compositions::relationship_graph::RelationshipGraph;
11use crate::connectives::accumulator::Accumulator;
12use crate::connectives::buffer::Buffer;
13use crate::connectives::marker::Marker;
14use crate::primitives::budget::Budget;
15
16verus! {
17
18pub const NODE_COST: u64 = 2;
20
21pub open spec fn marked_count(markers: Seq<Marker>, n: int) -> int
23 recommends 0 <= n <= markers.len(),
24 decreases n,
25{
26 if n <= 0 {
27 0
28 } else {
29 marked_count(markers, n - 1) + if markers[n - 1].marked { 1int } else { 0int }
30 }
31}
32
33pub struct TraversalEngine {
35 pub num_nodes: usize,
37 pub root: usize,
39 pub graph: RelationshipGraph,
41 pub budget: Budget,
43 pub visited: Vec<Marker>,
45 pub accepted: Accumulator<usize>,
47 pub queue: Buffer<usize>,
49}
50
51impl TraversalEngine {
52 pub open spec fn all_valid(values: Seq<usize>, num_nodes: usize) -> bool {
54 forall|index: int| 0 <= index < values.len() ==>
55 #[trigger] values[index] < num_nodes
56 }
57
58 pub open spec fn accepted_contains_spec(&self, node: usize) -> bool {
60 crate::connectives::buffer::contains_value(self.accepted.accumulated@, node)
61 }
62
63 pub open spec fn queue_contains_spec(&self, node: usize) -> bool {
65 crate::connectives::buffer::contains_value(self.queue.values@, node)
66 }
67
68 pub open spec fn visited_contains_spec(&self, node: usize) -> bool {
70 node < self.visited.len() && self.visited@[node as int].marked
71 }
72
73 pub open spec fn full_topology(&self) -> bool {
75 forall|source: usize, target: usize|
76 source < self.num_nodes && target < self.num_nodes ==>
77 #[trigger] self.graph.edge_proj(source, target)
78 == (source == self.root && target != self.root)
79 }
80
81 pub open spec fn partial_topology(
83 graph: &RelationshipGraph,
84 root: usize,
85 loaded_targets: usize,
86 ) -> bool {
87 forall|source: usize, target: usize|
88 source < graph.num_nodes && target < graph.num_nodes ==>
89 #[trigger] graph.edge_proj(source, target)
90 == (source == root && target < loaded_targets && target != root)
91 }
92
93 pub open spec fn root_frontier_gate(&self) -> bool {
95 !self.visited@[self.root as int].marked ==>
96 forall|node: usize| #[trigger] self.queue_contains_spec(node) ==> node == self.root
97 }
98
99 pub open spec fn accepted_subset_visited(&self) -> bool {
101 forall|node: usize| #[trigger] self.accepted_contains_spec(node) ==>
102 node < self.num_nodes && self.visited_contains_spec(node)
103 }
104
105 pub open spec fn budget_invariant(&self) -> bool {
107 &&& self.budget.safety_invariant()
108 &&& self.budget.reserved == 0
109 &&& self.budget.pending_eviction == 0
110 }
111
112 pub open spec fn type_invariant(&self) -> bool {
114 &&& self.root < self.num_nodes
115 &&& self.graph.num_nodes == self.num_nodes
116 &&& self.graph.max_weight == 0
117 &&& self.graph.inv()
118 &&& self.full_topology()
119 &&& self.visited@.len() == self.num_nodes
120 &&& self.queue.well_formed()
121 &&& self.queue.capacity == self.num_nodes
122 &&& Self::all_valid(self.queue.values@, self.num_nodes)
123 &&& crate::connectives::buffer::all_distinct(self.queue.values@)
124 &&& self.accepted.well_formed()
125 &&& self.accepted.pending@.len() == 0
126 &&& Self::all_valid(self.accepted.accumulated@, self.num_nodes)
127 &&& crate::connectives::buffer::all_distinct(self.accepted.accumulated@)
128 }
129
130 pub open spec fn inv(&self) -> bool {
132 &&& self.type_invariant()
133 &&& self.budget_invariant()
134 &&& self.accepted_subset_visited()
135 &&& self.root_frontier_gate()
136 }
137
138 pub proof fn expose(&self)
140 requires self.inv(),
141 ensures
142 self.type_invariant(),
143 self.budget_invariant(),
144 self.accepted_subset_visited(),
145 self.root_frontier_gate(),
146 self.root < self.num_nodes,
147 self.visited@.len() == self.num_nodes,
148 self.full_topology(),
149 self.queue.well_formed(),
150 self.accepted.well_formed(),
151 self.accepted.pending@.len() == 0,
152 crate::connectives::buffer::all_distinct(self.queue.values@),
153 Self::all_valid(self.queue.values@, self.num_nodes),
154 crate::connectives::buffer::all_distinct(self.accepted.accumulated@),
155 Self::all_valid(self.accepted.accumulated@, self.num_nodes),
156 forall|candidate: usize|
157 #[trigger] self.accepted_contains_spec(candidate) ==>
158 candidate < self.num_nodes && self.visited_contains_spec(candidate),
159 !self.visited@[self.root as int].marked ==>
160 forall|candidate: usize| #[trigger] self.queue_contains_spec(candidate) ==>
161 candidate == self.root,
162 {
163 reveal(TraversalEngine::inv);
164 reveal(TraversalEngine::type_invariant);
165 reveal(TraversalEngine::accepted_subset_visited);
166 reveal(TraversalEngine::root_frontier_gate);
167 }
168
169 pub fn new(num_nodes: usize, root: usize, max_budget: u64) -> (engine: TraversalEngine)
171 requires root < num_nodes,
172 ensures
173 engine.inv(),
174 engine.num_nodes == num_nodes,
175 engine.root == root,
176 engine.budget.capacity == max_budget,
177 engine.budget.allocated == 0,
178 engine.queue.values@ == seq![root],
179 engine.accepted.original@.len() == 0,
180 engine.accepted.accumulated@.len() == 0,
181 engine.accepted.pending@.len() == 0,
182 forall|node: int| 0 <= node < engine.visited@.len() ==>
183 !#[trigger] engine.visited@[node].marked,
184 {
185 let mut graph = RelationshipGraph::new(num_nodes, 0);
186 assert(Self::partial_topology(&graph, root, 0)) by {
187 assert forall|source: usize, target: usize|
188 source < graph.num_nodes && target < graph.num_nodes implies
189 #[trigger] graph.edge_proj(source, target)
190 == (source == root && target < 0 && target != root) by {
191 if graph.edge_proj(source, target) {
192 let entry = choose|entry: int|
193 0 <= entry < graph.registry.entries@.len()
194 && graph.registry.entries@[entry].0.0 == source
195 && graph.registry.entries@[entry].0.1 == target;
196 assert(false);
197 }
198 }
199 }
200 let mut target: usize = 0;
201 while target < num_nodes
202 invariant
203 root < num_nodes,
204 graph.num_nodes == num_nodes,
205 graph.max_weight == 0,
206 graph.inv(),
207 target <= num_nodes,
208 Self::partial_topology(&graph, root, target),
209 decreases num_nodes - target,
210 {
211 if target != root {
212 proof {
213 graph.exact_edge_implies_pair(root, target, 0);
214 assert(!graph.edge_proj(root, target));
215 assert(!graph.exact_edge(root, target, 0));
216 }
217 let added = graph.add_edge(root, target, 0);
218 assert(added);
219 let _ = added;
220 }
221 let next_target = target + 1;
222 assert(Self::partial_topology(&graph, root, next_target)) by {
223 assert forall|source: usize, destination: usize|
224 source < graph.num_nodes && destination < graph.num_nodes implies
225 #[trigger] graph.edge_proj(source, destination)
226 == (source == root
227 && destination < next_target
228 && destination != root) by {
229 if target == root {
230 if destination != root {
231 if destination < next_target {
232 assert(destination <= target);
233 assert(destination < target);
234 }
235 if destination < target {
236 assert(destination < next_target);
237 }
238 }
239 }
240 }
241 }
242 target = next_target;
243 }
244
245 let mut visited: Vec<Marker> = Vec::new();
246 let mut node: usize = 0;
247 while node < num_nodes
248 invariant
249 node <= num_nodes,
250 visited@.len() == node,
251 forall|index: int| 0 <= index < visited@.len() ==>
252 !#[trigger] visited@[index].marked,
253 decreases num_nodes - node,
254 {
255 visited.push(Marker::new(false));
256 node = node + 1;
257 }
258
259 let budget = Budget::new(max_budget);
260 let accepted = Accumulator::from_accumulated(Vec::new());
261 let mut queue = Buffer::new(num_nodes);
262 let queued = queue.push(root);
263 let _ = queued;
264 assert(queue.values@ == seq![root]);
265 assert(crate::connectives::buffer::all_distinct(queue.values@));
266
267 let engine = TraversalEngine {
268 num_nodes,
269 root,
270 graph,
271 budget,
272 visited,
273 accepted,
274 queue,
275 };
276 assert(engine.full_topology()) by {
277 assert forall|source: usize, destination: usize|
278 source < engine.num_nodes && destination < engine.num_nodes implies
279 #[trigger] engine.graph.edge_proj(source, destination)
280 == (source == engine.root && destination != engine.root) by {
281 }
282 }
283 assert(engine.accepted_subset_visited());
284 assert(engine.root_frontier_gate());
285 engine
286 }
287
288 pub fn budget_remaining(&self) -> (remaining: u64)
290 requires self.budget_invariant(),
291 ensures remaining as int == self.budget.capacity as int - self.budget.allocated as int,
292 {
293 self.budget.available()
294 }
295
296 pub fn queue_contains(&self, node: usize) -> (present: bool)
298 ensures present == self.queue_contains_spec(node),
299 {
300 self.queue.contains(node)
301 }
302
303 pub fn visited_contains(&self, node: usize) -> (present: bool)
305 ensures present == self.visited_contains_spec(node),
306 {
307 if node >= self.visited.len() { false } else { self.visited[node].is_marked() }
308 }
309
310 pub fn accepted_contains(&self, node: usize) -> (present: bool)
312 ensures present == self.accepted_contains_spec(node),
313 {
314 crate::connectives::buffer::retained_contains(&self.accepted.accumulated, node)
315 }
316
317 pub fn can_visit(&self, node: usize) -> (enabled: bool)
319 ensures enabled == (node < self.num_nodes
320 && self.queue_contains_spec(node)
321 && !self.visited_contains_spec(node)),
322 {
323 node < self.num_nodes && self.queue_contains(node) && !self.visited_contains(node)
324 }
325
326 pub fn can_skip(&self, node: usize) -> (enabled: bool)
328 ensures enabled == (node < self.num_nodes && self.queue_contains_spec(node)),
329 {
330 node < self.num_nodes && self.queue_contains(node)
331 }
332
333 pub fn can_terminate(&self) -> (enabled: bool)
335 ensures enabled == (self.queue.values@.len() == 0),
336 {
337 self.queue.is_empty()
338 }
339
340 pub fn visited_count(&self) -> (count: usize)
342 ensures count as int == marked_count(self.visited@, self.visited@.len() as int),
343 {
344 let mut count: usize = 0;
345 let mut index: usize = 0;
346 while index < self.visited.len()
347 invariant
348 index <= self.visited.len(),
349 count <= index,
350 count as int == marked_count(self.visited@, index as int),
351 decreases self.visited.len() - index,
352 {
353 if self.visited[index].is_marked() {
354 count = count + 1;
355 }
356 index = index + 1;
357 }
358 count
359 }
360
361 fn enqueue_star_children(
362 graph: &RelationshipGraph,
363 queue: &mut Buffer<usize>,
364 root: usize,
365 num_nodes: usize,
366 )
367 requires
368 root < num_nodes,
369 graph.num_nodes == num_nodes,
370 graph.inv(),
371 forall|source: usize, target: usize|
372 source < num_nodes && target < num_nodes ==>
373 #[trigger] graph.edge_proj(source, target)
374 == (source == root && target != root),
375 old(queue).well_formed(),
376 old(queue).capacity == num_nodes,
377 old(queue).values@.len() == 0,
378 ensures
379 final(queue).well_formed(),
380 final(queue).capacity == old(queue).capacity,
381 final(queue).values@.len() == num_nodes - 1,
382 forall|index: int| 0 <= index < final(queue).values@.len() ==>
383 #[trigger] final(queue).values@[index]
384 == if index < root as int {
385 index as usize
386 } else {
387 (index + 1) as usize
388 },
389 crate::connectives::buffer::all_distinct(final(queue).values@),
390 Self::all_valid(final(queue).values@, num_nodes),
391 forall|candidate: usize|
392 #[trigger] crate::connectives::buffer::contains_value(
393 final(queue).values@,
394 candidate,
395 ) == (candidate < num_nodes && candidate != root),
396 {
397 let mut target: usize = 0;
398 while target < num_nodes
399 invariant
400 root < num_nodes,
401 graph.num_nodes == num_nodes,
402 graph.inv(),
403 forall|source: usize, destination: usize|
404 source < num_nodes && destination < num_nodes ==>
405 #[trigger] graph.edge_proj(source, destination)
406 == (source == root && destination != root),
407 target <= num_nodes,
408 queue.well_formed(),
409 queue.capacity == num_nodes,
410 crate::connectives::buffer::all_distinct(queue.values@),
411 Self::all_valid(queue.values@, num_nodes),
412 queue.values@.len()
413 == target - if root < target { 1usize } else { 0usize },
414 forall|index: int| 0 <= index < queue.values@.len() ==>
415 #[trigger] queue.values@[index]
416 == if index < root as int {
417 index as usize
418 } else {
419 (index + 1) as usize
420 },
421 forall|candidate: usize|
422 #[trigger] crate::connectives::buffer::contains_value(
423 queue.values@,
424 candidate,
425 ) == (candidate < target && candidate != root),
426 decreases num_nodes - target,
427 {
428 let ghost before_queue = queue.values@;
429 let edge = graph.contains_pair(root, target);
430 assert(edge == (target != root));
431 if edge {
432 assert(!crate::connectives::buffer::contains_value(before_queue, target));
433 assert(queue.values@.len() < queue.capacity);
434 let queued = queue.push_unique(target);
435 assert(queued);
436 let _ = queued;
437 assert(Self::all_valid(queue.values@, num_nodes)) by {
438 assert forall|index: int| 0 <= index < queue.values@.len()
439 implies #[trigger] queue.values@[index] < num_nodes by {
440 if index == before_queue.len() {
441 assert(queue.values@[index] == target);
442 } else {
443 assert(index < before_queue.len());
444 assert(queue.values@[index] == before_queue[index]);
445 }
446 }
447 }
448 }
449 assert(queue.values@.len()
450 == (target + 1) - if root < target + 1 { 1usize } else { 0usize });
451 assert forall|index: int| 0 <= index < queue.values@.len() implies
452 #[trigger] queue.values@[index]
453 == if index < root as int {
454 index as usize
455 } else {
456 (index + 1) as usize
457 } by {
458 if edge && index == before_queue.len() {
459 assert(queue.values@[index] == target);
460 if target < root {
461 assert(index == target as int);
462 } else {
463 assert(target > root);
464 assert(index + 1 == target as int);
465 }
466 }
467 }
468 let next_target = target + 1;
469 assert forall|candidate: usize|
470 #[trigger] crate::connectives::buffer::contains_value(
471 queue.values@,
472 candidate,
473 ) == (candidate < next_target && candidate != root) by {
474 if edge {
475 crate::connectives::buffer::lemma_push_contains(
476 before_queue,
477 target,
478 candidate,
479 );
480 } else {
481 assert(queue.values@ == before_queue);
482 }
483 if target == root && candidate != root {
484 if candidate < next_target {
485 assert(candidate <= target);
486 assert(candidate < target);
487 }
488 }
489 }
490 target = next_target;
491 }
492 }
493
494 pub fn visit_node(&mut self, node: usize)
496 requires
497 old(self).inv(),
498 node < old(self).num_nodes,
499 old(self).queue_contains_spec(node),
500 !old(self).visited_contains_spec(node),
501 ensures
502 final(self).inv(),
503 final(self).num_nodes == old(self).num_nodes,
504 final(self).root == old(self).root,
505 final(self).graph == old(self).graph,
506 final(self).budget.capacity == old(self).budget.capacity,
507 final(self).budget.reserved == old(self).budget.reserved,
508 final(self).budget.pending_eviction == old(self).budget.pending_eviction,
509 final(self).budget.allocated as int
510 == if old(self).budget.allocated as int + NODE_COST as int
511 <= old(self).budget.capacity as int {
512 old(self).budget.allocated as int + NODE_COST as int
513 } else {
514 old(self).budget.allocated as int
515 },
516 final(self).accepted.original@ == if old(self).budget.allocated as int
517 + NODE_COST as int <= old(self).budget.capacity as int {
518 old(self).accepted.original@.push(node)
519 } else {
520 old(self).accepted.original@
521 },
522 final(self).accepted.accumulated@ == if old(self).budget.allocated as int
523 + NODE_COST as int <= old(self).budget.capacity as int {
524 old(self).accepted.accumulated@.push(node)
525 } else {
526 old(self).accepted.accumulated@
527 },
528 final(self).accepted.pending@ == old(self).accepted.pending@,
529 forall|candidate: usize|
530 candidate < old(self).num_nodes ==>
531 #[trigger] final(self).visited_contains_spec(candidate)
532 == (old(self).visited_contains_spec(candidate) || candidate == node),
533 forall|candidate: usize|
534 #[trigger] final(self).accepted_contains_spec(candidate)
535 == (old(self).accepted_contains_spec(candidate)
536 || (old(self).budget.allocated as int + NODE_COST as int
537 <= old(self).budget.capacity as int
538 && candidate == node)),
539 forall|candidate: usize|
540 #[trigger] final(self).queue_contains_spec(candidate)
541 == if old(self).budget.allocated as int + NODE_COST as int
542 <= old(self).budget.capacity as int
543 && node == old(self).root {
544 (old(self).queue_contains_spec(candidate) && candidate != node)
545 || (candidate < old(self).num_nodes
546 && candidate != old(self).root)
547 } else {
548 old(self).queue_contains_spec(candidate) && candidate != node
549 },
550 (old(self).budget.allocated as int + NODE_COST as int
551 <= old(self).budget.capacity as int
552 && node == old(self).root) ==> {
553 &&& final(self).queue.values@.len() == old(self).num_nodes - 1
554 &&& forall|index: int| 0 <= index < final(self).queue.values@.len() ==>
555 #[trigger] final(self).queue.values@[index]
556 == if index < old(self).root as int {
557 index as usize
558 } else {
559 (index + 1) as usize
560 }
561 },
562 (!(old(self).budget.allocated as int + NODE_COST as int
563 <= old(self).budget.capacity as int
564 && node == old(self).root)) ==> exists|index: int|
565 0 <= index < old(self).queue.values@.len()
566 && old(self).queue.values@[index] == node
567 && final(self).queue.values@
568 == old(self).queue.values@.remove(index),
569 final(self).queue.capacity == old(self).queue.capacity,
570 {
571 proof { self.expose(); }
572 let num_nodes = self.num_nodes;
573 let root = self.root;
574 let initial_allocated = self.budget.allocated;
575 let budget_capacity = self.budget.capacity;
576 let _ = (initial_allocated, budget_capacity);
577 let ghost old_accepted = self.accepted.accumulated@;
578 let ghost old_visited = self.visited@;
579 let ghost old_queue = self.queue.values@;
580 proof {
581 reveal(TraversalEngine::accepted_contains_spec);
582 reveal(TraversalEngine::queue_contains_spec);
583 reveal(TraversalEngine::visited_contains_spec);
584 assert forall|candidate: usize|
585 crate::connectives::buffer::contains_value(old_accepted, candidate) implies
586 candidate < self.num_nodes && old_visited[candidate as int].marked by {
587 assert(self.accepted_contains_spec(candidate));
588 assert(self.visited_contains_spec(candidate));
589 }
590 assert(!old_visited[node as int].marked);
591 assert(crate::connectives::buffer::contains_value(old_queue, node));
592 assert(!old_visited[root as int].marked ==> forall|candidate: usize|
593 #[trigger] crate::connectives::buffer::contains_value(old_queue, candidate)
594 ==> candidate == root) by {
595 if !old_visited[root as int].marked {
596 assert(!self.visited@[root as int].marked);
597 assert forall|candidate: usize|
598 #[trigger] crate::connectives::buffer::contains_value(
599 old_queue,
600 candidate,
601 ) implies candidate == root by {
602 assert(self.queue_contains_spec(candidate));
603 }
604 }
605 }
606 assert(self.full_topology());
607 assert(Self::all_valid(old_queue, num_nodes));
608 assert(crate::connectives::buffer::all_distinct(old_queue));
609 assert(Self::all_valid(old_accepted, num_nodes));
610 assert(crate::connectives::buffer::all_distinct(old_accepted));
611 }
612
613 let removed = self.queue.remove_value(node);
614 assert(removed);
615 let _ = removed;
616 let ghost queue_after_removal = self.queue.values@;
617
618 let mut marker = self.visited[node];
619 let changed = marker.set();
620 assert(changed);
621 let _ = changed;
622 self.visited.set(node, marker);
623 assert(self.visited@ == old_visited.update(node as int, marker));
624 assert forall|candidate: usize| candidate < self.num_nodes implies
625 #[trigger] self.visited_contains_spec(candidate)
626 == (candidate == node || old_visited[candidate as int].marked) by {
627 }
628
629 let accepted = self.budget.try_allocate(NODE_COST);
630 assert(accepted == (initial_allocated as int + NODE_COST as int
631 <= budget_capacity as int));
632 if accepted {
633 assert(!crate::connectives::buffer::contains_value(old_accepted, node)) by {
634 if crate::connectives::buffer::contains_value(old_accepted, node) {
635 assert(old_visited[node as int].marked);
636 }
637 }
638 self.accepted.append(node);
639 assert(self.accepted.accumulated@ == old_accepted.push(node));
640 proof {
641 crate::connectives::buffer::lemma_push_contains(old_accepted, node, node);
642 assert forall|candidate: usize|
643 #[trigger] crate::connectives::buffer::contains_value(
644 self.accepted.accumulated@,
645 candidate,
646 ) == (crate::connectives::buffer::contains_value(
647 old_accepted,
648 candidate,
649 ) || candidate == node) by {
650 crate::connectives::buffer::lemma_push_contains(
651 old_accepted,
652 node,
653 candidate,
654 );
655 }
656 }
657 assert(crate::connectives::buffer::all_distinct(self.accepted.accumulated@)) by {
658 assert forall|left: int, right: int|
659 0 <= left < self.accepted.accumulated@.len()
660 && 0 <= right < self.accepted.accumulated@.len()
661 && left != right
662 implies #[trigger] self.accepted.accumulated@[left]
663 != #[trigger] self.accepted.accumulated@[right] by {
664 if left < old_accepted.len() && right < old_accepted.len() {
665 } else if left == old_accepted.len() && right < old_accepted.len() {
666 crate::connectives::buffer::indexed_value_contained(
667 old_accepted,
668 right,
669 );
670 assert(crate::connectives::buffer::contains_value(
671 old_accepted,
672 old_accepted[right],
673 ));
674 } else if right == old_accepted.len() && left < old_accepted.len() {
675 crate::connectives::buffer::indexed_value_contained(
676 old_accepted,
677 left,
678 );
679 assert(crate::connectives::buffer::contains_value(
680 old_accepted,
681 old_accepted[left],
682 ));
683 }
684 }
685 }
686
687 if node == root {
688 assert(self.queue.values@.len() == 0) by {
689 if self.queue.values@.len() > 0 {
690 let queued = self.queue.values@[0];
691 crate::connectives::buffer::indexed_value_contained(
692 self.queue.values@,
693 0,
694 );
695 assert(self.queue_contains_spec(queued));
696 assert(crate::connectives::buffer::contains_value(old_queue, queued));
697 assert(queued == root);
698 assert(!self.queue_contains_spec(root));
699 }
700 }
701 Self::enqueue_star_children(
702 &self.graph,
703 &mut self.queue,
704 root,
705 num_nodes,
706 );
707 }
708 } else {
709 assert(self.accepted.accumulated@ == old_accepted);
710 }
711
712 assert(Self::all_valid(self.accepted.accumulated@, self.num_nodes)) by {
713 assert forall|index: int| 0 <= index < self.accepted.accumulated@.len()
714 implies #[trigger] self.accepted.accumulated@[index] < self.num_nodes by {
715 if accepted {
716 if index == old_accepted.len() {
717 assert(self.accepted.accumulated@[index] == node);
718 } else {
719 assert(index < old_accepted.len());
720 assert(self.accepted.accumulated@[index] == old_accepted[index]);
721 }
722 }
723 }
724 }
725 assert forall|candidate: usize|
726 #[trigger] self.accepted_contains_spec(candidate)
727 == (crate::connectives::buffer::contains_value(old_accepted, candidate)
728 || (accepted && candidate == node)) by {
729 reveal(TraversalEngine::accepted_contains_spec);
730 if accepted {
731 crate::connectives::buffer::lemma_push_contains(
732 old_accepted,
733 node,
734 candidate,
735 );
736 }
737 }
738 assert(self.accepted_subset_visited()) by {
739 assert forall|candidate: usize| #[trigger] self.accepted_contains_spec(candidate)
740 implies candidate < self.num_nodes && self.visited_contains_spec(candidate) by {
741 if accepted && candidate == node {
742 } else {
743 assert(crate::connectives::buffer::contains_value(old_accepted, candidate));
744 assert(old_visited[candidate as int].marked);
745 }
746 }
747 }
748 assert forall|candidate: usize|
749 #[trigger] self.queue_contains_spec(candidate)
750 == if accepted && node == root {
751 (crate::connectives::buffer::contains_value(old_queue, candidate)
752 && candidate != node)
753 || (candidate < num_nodes && candidate != root)
754 } else {
755 crate::connectives::buffer::contains_value(old_queue, candidate)
756 && candidate != node
757 } by {
758 reveal(TraversalEngine::queue_contains_spec);
759 if accepted && node == root {
760 assert(self.queue_contains_spec(candidate)
761 == (candidate < num_nodes && candidate != root));
762 } else {
763 assert(self.queue.values@ == queue_after_removal);
764 }
765 }
766 assert(self.visited@[root as int].marked) by {
767 if old_visited[root as int].marked {
768 if node != root {
769 assert(self.visited@[root as int] == old_visited[root as int]);
770 }
771 } else {
772 assert(node == root) by {
773 assert(crate::connectives::buffer::contains_value(old_queue, node));
774 }
775 }
776 }
777 assert(self.root_frontier_gate());
778 assert(self.num_nodes == num_nodes);
779 assert(self.root == root);
780 assert(Self::all_valid(self.queue.values@, self.num_nodes)) by {
781 assert forall|index: int| 0 <= index < self.queue.values@.len()
782 implies #[trigger] self.queue.values@[index] < self.num_nodes by {
783 crate::connectives::buffer::indexed_value_contained(
784 self.queue.values@,
785 index,
786 );
787 let candidate = self.queue.values@[index];
788 if !accepted || node != root {
789 assert(crate::connectives::buffer::contains_value(old_queue, candidate));
790 let old_index = choose|old_index: int|
791 0 <= old_index < old_queue.len() && old_queue[old_index] == candidate;
792 assert(old_queue[old_index] < num_nodes);
793 }
794 }
795 }
796 assert(self.type_invariant()) by {
797 reveal(TraversalEngine::type_invariant);
798 }
799 assert(self.budget_invariant()) by {
800 reveal(TraversalEngine::budget_invariant);
801 }
802 assert(self.inv()) by {
803 reveal(TraversalEngine::inv);
804 }
805 }
806
807 pub fn skip(&mut self, node: usize)
809 requires
810 old(self).inv(),
811 node < old(self).num_nodes,
812 old(self).queue_contains_spec(node),
813 ensures
814 final(self).inv(),
815 final(self).num_nodes == old(self).num_nodes,
816 final(self).root == old(self).root,
817 final(self).graph == old(self).graph,
818 final(self).budget == old(self).budget,
819 final(self).visited@ == old(self).visited@,
820 final(self).accepted == old(self).accepted,
821 final(self).queue.capacity == old(self).queue.capacity,
822 exists|index: int|
823 0 <= index < old(self).queue.values@.len()
824 && old(self).queue.values@[index] == node
825 && final(self).queue.values@
826 == old(self).queue.values@.remove(index),
827 forall|candidate: usize| #[trigger] final(self).queue_contains_spec(candidate)
828 == (old(self).queue_contains_spec(candidate) && candidate != node),
829 {
830 proof { self.expose(); }
831 let root = self.root;
832 let num_nodes = self.num_nodes;
833 let _ = (root, num_nodes);
834 let ghost old_queue = self.queue.values@;
835 let ghost old_visited = self.visited@;
836 let ghost old_accepted = self.accepted.accumulated@;
837 proof {
838 reveal(TraversalEngine::queue_contains_spec);
839 reveal(TraversalEngine::accepted_contains_spec);
840 reveal(TraversalEngine::visited_contains_spec);
841 assert(!old_visited[root as int].marked ==> forall|candidate: usize|
842 #[trigger] crate::connectives::buffer::contains_value(old_queue, candidate)
843 ==> candidate == root) by {
844 if !old_visited[root as int].marked {
845 assert(!self.visited@[root as int].marked);
846 assert forall|candidate: usize|
847 #[trigger] crate::connectives::buffer::contains_value(
848 old_queue,
849 candidate,
850 ) implies candidate == root by {
851 assert(self.queue_contains_spec(candidate));
852 }
853 }
854 }
855 assert(Self::all_valid(old_queue, num_nodes));
856 assert forall|candidate: usize|
857 crate::connectives::buffer::contains_value(old_accepted, candidate) implies
858 candidate < num_nodes && old_visited[candidate as int].marked by {
859 assert(self.accepted_contains_spec(candidate));
860 assert(self.visited_contains_spec(candidate));
861 }
862 }
863 let removed = self.queue.remove_value(node);
864 assert(removed);
865 let _ = removed;
866 assert(self.root_frontier_gate()) by {
867 if !self.visited@[root as int].marked {
868 assert forall|candidate: usize| #[trigger] self.queue_contains_spec(candidate)
869 implies candidate == root by {
870 assert(crate::connectives::buffer::contains_value(old_queue, candidate));
871 }
872 }
873 }
874 assert(Self::all_valid(self.queue.values@, self.num_nodes)) by {
875 assert forall|index: int| 0 <= index < self.queue.values@.len()
876 implies #[trigger] self.queue.values@[index] < self.num_nodes by {
877 crate::connectives::buffer::indexed_value_contained(
878 self.queue.values@,
879 index,
880 );
881 let candidate = self.queue.values@[index];
882 assert(crate::connectives::buffer::contains_value(old_queue, candidate));
883 let old_index = choose|old_index: int|
884 0 <= old_index < old_queue.len() && old_queue[old_index] == candidate;
885 assert(old_queue[old_index] < num_nodes);
886 }
887 }
888 assert(self.type_invariant()) by {
889 reveal(TraversalEngine::type_invariant);
890 }
891 assert(self.budget_invariant());
892 assert(self.accepted.accumulated@ == old_accepted);
893 assert(self.visited@ == old_visited);
894 assert(self.accepted_subset_visited()) by {
895 assert forall|candidate: usize| #[trigger] self.accepted_contains_spec(candidate)
896 implies candidate < self.num_nodes && self.visited_contains_spec(candidate) by {
897 assert(crate::connectives::buffer::contains_value(old_accepted, candidate));
898 assert(old_visited[candidate as int].marked);
899 }
900 }
901 assert(self.inv()) by {
902 reveal(TraversalEngine::inv);
903 }
904 }
905
906 pub fn terminate(&mut self)
908 requires
909 old(self).inv(),
910 old(self).queue.values@.len() == 0,
911 ensures final(self).inv(), *final(self) == *old(self),
912 {
913 }
914}
915
916}