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