1use crate::api::values_within_max;
4use crate::compositions::allocation_snapshot::AllocationSnapshot as AllocationSnapshotCarrier;
5use crate::compositions::bisection::Bisection as BisectionCarrier;
6use crate::compositions::equivalence_class::EquivalenceClass as EquivalenceClassCarrier;
7use crate::compositions::federated_budget::FederatedBudget as FederatedBudgetCarrier;
8use crate::compositions::rate_limit::RateLimit as RateLimitCarrier;
9use crate::compositions::reduction::Reducer as ReductionCarrier;
10use crate::compositions::relationship_graph::RelationshipGraph as RelationshipGraphCarrier;
11use crate::compositions::sampler::Sampler as SamplerCarrier;
12use crate::compositions::signal::Signal as SignalCarrier;
13use crate::compositions::traversal_engine::TraversalEngine as TraversalEngineCarrier;
14use vstd::prelude::*;
15
16verus! {
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20#[non_exhaustive]
21pub enum AllocationSnapshotError {
22 NodeOutOfRange,
24 NodeAlreadyAccepted,
26 ZeroCost,
28 InsufficientBudget,
30}
31
32pub struct AllocationSnapshot {
34 inner: AllocationSnapshotCarrier,
35}
36
37impl AllocationSnapshot {
38 #[verifier::type_invariant]
39 closed spec fn well_formed(&self) -> bool {
40 self.inner.type_invariant() && self.inner.budget_consistency()
41 }
42
43 pub fn new(capacity: u64, num_nodes: u64) -> (snapshot: Self) {
45 Self { inner: AllocationSnapshotCarrier::new(capacity, num_nodes) }
46 }
47
48 pub fn capacity(&self) -> u64 { self.inner.capacity }
50
51 pub fn num_nodes(&self) -> u64 { self.inner.num_nodes }
53
54 pub fn total_cost(&self) -> u64 { self.inner.total_cost }
56
57 pub fn budget_remaining(&self) -> u64 { self.inner.budget_remaining }
59
60 pub fn len(&self) -> usize { self.inner.accepted.len() }
62
63 pub fn is_empty(&self) -> bool { self.inner.accepted.is_empty() }
65
66 pub fn contains(&self, node: u64) -> bool { self.inner.contains_exec(node) }
68
69 #[expect(clippy::indexing_slicing, reason = "the branch proves the accepted-node index is in bounds")]
71 pub fn accepted(&self, index: usize) -> Option<u64> {
72 if index < self.inner.accepted.len() { Some(self.inner.accepted[index]) } else { None }
73 }
74
75 pub fn accept(&mut self, node: u64, cost: u64) -> (result: Result<(), AllocationSnapshotError>) {
77 proof { use_type_invariant(&*self); }
78 if node >= self.inner.num_nodes { return Err(AllocationSnapshotError::NodeOutOfRange); }
79 if self.inner.contains_exec(node) { return Err(AllocationSnapshotError::NodeAlreadyAccepted); }
80 if cost == 0 { return Err(AllocationSnapshotError::ZeroCost); }
81 if cost > self.inner.budget_remaining { return Err(AllocationSnapshotError::InsufficientBudget); }
82 let mut carrier = allocation_snapshot_sentinel();
83 core::mem::swap(&mut self.inner, &mut carrier);
84 carrier.accept_node(node, cost);
85 core::mem::swap(&mut self.inner, &mut carrier);
86 Ok(())
87 }
88}
89
90pub struct FederatedBudget {
92 inner: FederatedBudgetCarrier,
93}
94
95impl FederatedBudget {
96 #[verifier::type_invariant]
97 closed spec fn well_formed(&self) -> bool { self.inner.inv() }
98
99 pub fn new(master_capacity: u64, num_pools: usize) -> (budget: Self) {
101 Self { inner: FederatedBudgetCarrier::new(master_capacity, num_pools) }
102 }
103
104 pub fn master_capacity(&self) -> u64 { self.inner.master_capacity }
106
107 pub fn master_allocated(&self) -> u64 { self.inner.master_allocated }
109
110 pub fn len(&self) -> usize { self.inner.sub_capacities.len() }
112
113 pub fn is_empty(&self) -> bool { self.inner.sub_capacities.is_empty() }
115
116 #[expect(clippy::indexing_slicing, reason = "the branch proves the pool index is in bounds")]
118 pub fn pool_capacity(&self, pool: usize) -> Option<u64> {
119 if pool < self.inner.sub_capacities.len() { Some(self.inner.sub_capacities[pool]) } else { None }
120 }
121
122 #[expect(clippy::indexing_slicing, reason = "the branch proves the pool index is in bounds")]
124 pub fn pool_allocated(&self, pool: usize) -> Option<u64> {
125 if pool < self.inner.sub_allocated.len() { Some(self.inner.sub_allocated[pool]) } else { None }
126 }
127
128 #[must_use]
130 pub fn try_delegate(&mut self, pool: usize, amount: u64) -> (accepted: bool) {
131 proof { use_type_invariant(&*self); }
132 let mut carrier = federated_budget_sentinel();
133 core::mem::swap(&mut self.inner, &mut carrier);
134 let accepted = carrier.allocate_sub_pool(pool, amount);
135 core::mem::swap(&mut self.inner, &mut carrier);
136 accepted
137 }
138
139 #[must_use]
141 pub fn try_allocate(&mut self, pool: usize, amount: u64) -> (accepted: bool) {
142 proof { use_type_invariant(&*self); }
143 let mut carrier = federated_budget_sentinel();
144 core::mem::swap(&mut self.inner, &mut carrier);
145 let accepted = carrier.allocate_from_sub_pool(pool, amount);
146 core::mem::swap(&mut self.inner, &mut carrier);
147 accepted
148 }
149
150 #[must_use]
152 pub fn try_release(&mut self, pool: usize, amount: u64) -> (accepted: bool) {
153 proof { use_type_invariant(&*self); }
154 let mut carrier = federated_budget_sentinel();
155 core::mem::swap(&mut self.inner, &mut carrier);
156 let accepted = carrier.release_from_sub_pool(pool, amount);
157 core::mem::swap(&mut self.inner, &mut carrier);
158 accepted
159 }
160}
161
162#[derive(Clone, Copy, Debug, Eq, PartialEq)]
164#[non_exhaustive]
165pub enum BisectionBuildError {
166 DomainTooSmall,
168 ThresholdOutOfRange,
170}
171
172#[derive(Clone, Copy, Debug, Eq, PartialEq)]
174#[non_exhaustive]
175pub enum BisectionError {
176 AlreadyConverged,
178}
179
180pub struct Bisection {
182 inner: BisectionCarrier,
183}
184
185impl Bisection {
186 #[verifier::type_invariant]
187 closed spec fn well_formed(&self) -> bool { self.inner.invariant() }
188
189 pub fn new(domain_size: u64, threshold: u64) -> (result: Result<Self, BisectionBuildError>) {
191 if domain_size < 2 { return Err(BisectionBuildError::DomainTooSmall); }
192 if threshold < 1 || threshold >= domain_size {
193 return Err(BisectionBuildError::ThresholdOutOfRange);
194 }
195 proof { lemma_u64_domain_fits_64(domain_size); }
196 let inner = BisectionCarrier::new(0, domain_size, threshold, domain_size, 64);
197 Ok(Self { inner })
198 }
199
200 pub fn lower(&self) -> u64 { self.inner.lo }
202
203 pub fn upper(&self) -> u64 { self.inner.hi }
205
206 pub fn threshold(&self) -> u64 { self.inner.threshold }
208
209 pub fn probes_taken(&self) -> u64 { self.inner.probes_taken }
211
212 pub fn max_probes(&self) -> u64 { self.inner.max_probes }
214
215 pub fn is_converged(&self) -> bool {
217 proof { use_type_invariant(&*self); }
218 self.inner.converged()
219 }
220
221 pub fn probe(&mut self) -> (result: Result<(), BisectionError>) {
223 proof { use_type_invariant(&*self); }
224 if self.inner.hi - self.inner.lo < 2 { return Err(BisectionError::AlreadyConverged); }
225 let mut carrier = bisection_sentinel();
226 core::mem::swap(&mut self.inner, &mut carrier);
227 carrier.probe();
228 core::mem::swap(&mut self.inner, &mut carrier);
229 Ok(())
230 }
231
232 pub fn converge(&mut self) {
234 proof { use_type_invariant(&*self); }
235 let mut carrier = bisection_sentinel();
236 core::mem::swap(&mut self.inner, &mut carrier);
237 carrier.bisect();
238 core::mem::swap(&mut self.inner, &mut carrier);
239 }
240}
241
242#[derive(Clone, Copy, Debug, Eq, PartialEq)]
244#[non_exhaustive]
245pub enum EquivalenceClassError {
246 ElementOutOfRange,
248}
249
250pub struct EquivalenceClass {
252 inner: EquivalenceClassCarrier,
253}
254
255impl EquivalenceClass {
256 #[verifier::type_invariant]
257 closed spec fn well_formed(&self) -> bool { self.inner.inv() }
258
259 pub fn new(elements: usize, max_unions: u64) -> (classes: Self) {
261 Self { inner: EquivalenceClassCarrier::new(elements, max_unions) }
262 }
263
264 pub fn len(&self) -> usize { self.inner.n }
266
267 pub fn is_empty(&self) -> bool { self.inner.n == 0 }
269
270 pub fn unions_performed(&self) -> u64 { self.inner.ops_done }
272
273 pub fn max_unions(&self) -> u64 { self.inner.max_ops }
275
276 pub fn representative(&self, element: usize) -> (result: Result<usize, EquivalenceClassError>) {
278 proof { use_type_invariant(&*self); }
279 if element >= self.inner.n { return Err(EquivalenceClassError::ElementOutOfRange); }
280 Ok(self.inner.find(element))
281 }
282
283 pub fn union(&mut self, left: usize, right: usize) -> (result: Result<bool, EquivalenceClassError>) {
285 proof { use_type_invariant(&*self); }
286 if left >= self.inner.n || right >= self.inner.n {
287 return Err(EquivalenceClassError::ElementOutOfRange);
288 }
289 let mut carrier = equivalence_class_sentinel();
290 core::mem::swap(&mut self.inner, &mut carrier);
291 let merged = carrier.union(left, right);
292 core::mem::swap(&mut self.inner, &mut carrier);
293 Ok(merged)
294 }
295
296 pub fn equivalent(&self, left: usize, right: usize) -> (result: Result<bool, EquivalenceClassError>) {
298 proof { use_type_invariant(&*self); }
299 if left >= self.inner.n || right >= self.inner.n {
300 return Err(EquivalenceClassError::ElementOutOfRange);
301 }
302 Ok(self.inner.same(left, right))
303 }
304}
305
306#[derive(Clone, Copy, Debug, Eq, PartialEq)]
308#[non_exhaustive]
309pub enum RateLimitBuildError {
310 ZeroLimit,
312}
313
314#[derive(Clone, Copy, Debug, Eq, PartialEq)]
316#[non_exhaustive]
317pub enum RateLimitError {
318 ClockExhausted,
320}
321
322pub struct RateLimit {
324 inner: RateLimitCarrier,
325}
326
327impl RateLimit {
328 #[verifier::type_invariant]
329 closed spec fn well_formed(&self) -> bool {
330 self.inner.type_invariant() && self.inner.window_start_not_future()
331 }
332
333 pub fn new(max_per_window: u64, window_duration: u64, max_clock: u64)
335 -> (result: Result<Self, RateLimitBuildError>) {
336 if max_per_window == 0 { return Err(RateLimitBuildError::ZeroLimit); }
337 Ok(Self { inner: RateLimitCarrier::new(max_per_window, window_duration, max_clock) })
338 }
339
340 pub fn max_per_window(&self) -> u64 { self.inner.max_per_window }
342
343 pub fn window_duration(&self) -> u64 { self.inner.window_duration }
345
346 pub fn count(&self) -> u64 { self.inner.count }
348
349 pub fn clock(&self) -> u64 { self.inner.clock }
351
352 pub fn window_start(&self) -> u64 { self.inner.window_start }
354
355 #[must_use]
357 pub fn try_acquire(&mut self) -> (accepted: bool) {
358 proof { use_type_invariant(&*self); }
359 let mut carrier = rate_limit_sentinel();
360 core::mem::swap(&mut self.inner, &mut carrier);
361 let accepted = carrier.try_acquire();
362 core::mem::swap(&mut self.inner, &mut carrier);
363 accepted
364 }
365
366 pub fn tick(&mut self) -> (result: Result<(), RateLimitError>) {
368 proof { use_type_invariant(&*self); }
369 if self.inner.clock >= self.inner.max_clock { return Err(RateLimitError::ClockExhausted); }
370 let mut carrier = rate_limit_sentinel();
371 core::mem::swap(&mut self.inner, &mut carrier);
372 carrier.tick();
373 core::mem::swap(&mut self.inner, &mut carrier);
374 Ok(())
375 }
376}
377
378#[derive(Clone, Copy, Debug, Eq, PartialEq)]
380#[non_exhaustive]
381pub enum ReductionBuildError {
382 TooManyItems,
384 ValueOutOfRange,
386}
387
388#[derive(Clone, Copy, Debug, Eq, PartialEq)]
390#[non_exhaustive]
391pub enum ReductionError {
392 Complete,
394}
395
396pub struct Reduction {
398 inner: ReductionCarrier,
399}
400
401impl Reduction {
402 #[verifier::type_invariant]
403 closed spec fn well_formed(&self) -> bool {
404 self.inner.partition() && self.inner.aggregate() && self.inner.bounded()
405 }
406
407 pub fn new(items: Vec<u64>) -> (result: Result<Self, ReductionBuildError>) {
409 if items.len() > 1_000_000_000 { return Err(ReductionBuildError::TooManyItems); }
410 if !values_within_max(&items, 1_000_000_000) {
411 return Err(ReductionBuildError::ValueOutOfRange);
412 }
413 Ok(Self { inner: ReductionCarrier::new(items) })
414 }
415
416 pub fn result(&self) -> u64 { self.inner.result }
418
419 pub fn processed_len(&self) -> usize { self.inner.processed.len() }
421
422 pub fn remaining_len(&self) -> usize { self.inner.remaining.len() }
424
425 pub fn is_complete(&self) -> bool { self.inner.done() }
427
428 pub fn process_next(&mut self) -> (result: Result<(), ReductionError>) {
430 proof { use_type_invariant(&*self); }
431 if self.inner.remaining.is_empty() { return Err(ReductionError::Complete); }
432 let mut carrier = reduction_sentinel();
433 core::mem::swap(&mut self.inner, &mut carrier);
434 carrier.process();
435 core::mem::swap(&mut self.inner, &mut carrier);
436 Ok(())
437 }
438}
439
440#[derive(Clone, Copy, Debug, Eq, PartialEq)]
442#[non_exhaustive]
443pub enum RelationshipGraphError {
444 NodeOutOfRange,
446 WeightOutOfRange,
448 SelfLoop,
450}
451
452pub struct RelationshipGraph {
454 inner: RelationshipGraphCarrier,
455}
456
457impl RelationshipGraph {
458 #[verifier::type_invariant]
459 closed spec fn well_formed(&self) -> bool { self.inner.inv() }
460
461 pub fn new(num_nodes: usize, max_weight: u64) -> (graph: Self) {
463 Self { inner: RelationshipGraphCarrier::new(num_nodes, max_weight) }
464 }
465
466 pub fn num_nodes(&self) -> usize { self.inner.num_nodes }
468
469 pub fn max_weight(&self) -> u64 { self.inner.max_weight }
471
472 pub fn edge_count(&self) -> usize { self.inner.edges.len() }
474
475 #[expect(clippy::indexing_slicing, reason = "the branch proves the edge index is in bounds")]
477 pub fn edge(&self, index: usize) -> Option<(usize, usize, u64)> {
478 if index < self.inner.edges.len() { Some(self.inner.edges[index]) } else { None }
479 }
480
481 pub fn contains(&self, source: usize, destination: usize) -> bool {
483 self.inner.contains_pair(source, destination)
484 }
485
486 pub fn add_edge(&mut self, source: usize, destination: usize, weight: u64)
488 -> (result: Result<bool, RelationshipGraphError>) {
489 proof { use_type_invariant(&*self); }
490 if source >= self.inner.num_nodes || destination >= self.inner.num_nodes {
491 return Err(RelationshipGraphError::NodeOutOfRange);
492 }
493 if weight > self.inner.max_weight { return Err(RelationshipGraphError::WeightOutOfRange); }
494 if source == destination { return Err(RelationshipGraphError::SelfLoop); }
495 let mut carrier = relationship_graph_sentinel();
496 core::mem::swap(&mut self.inner, &mut carrier);
497 let added = carrier.add_edge(source, destination, weight);
498 core::mem::swap(&mut self.inner, &mut carrier);
499 Ok(added)
500 }
501
502 pub fn remove_edges(&mut self, source: usize, destination: usize) {
504 proof { use_type_invariant(&*self); }
505 let mut carrier = relationship_graph_sentinel();
506 core::mem::swap(&mut self.inner, &mut carrier);
507 carrier.remove_edge(source, destination);
508 core::mem::swap(&mut self.inner, &mut carrier);
509 }
510}
511
512#[derive(Clone, Copy, Debug, Eq, PartialEq)]
514#[non_exhaustive]
515pub enum SamplerError {
516 ItemOutOfRange,
518 SampleFull,
520 OutsideSupport,
522 AlreadySelected,
524}
525
526pub struct Sampler {
528 inner: SamplerCarrier,
529}
530
531impl Sampler {
532 #[verifier::type_invariant]
533 closed spec fn well_formed(&self) -> bool { self.inner.inv() }
534
535 pub fn new(distribution: Vec<u64>, sample_size: usize) -> (sampler: Self) {
537 Self { inner: SamplerCarrier::new(distribution, sample_size) }
538 }
539
540 pub fn len(&self) -> usize { self.inner.num_items }
542
543 pub fn is_empty(&self) -> bool { self.inner.num_items == 0 }
545
546 pub fn sample_size(&self) -> usize { self.inner.sample_size }
548
549 pub fn selected_len(&self) -> usize { self.inner.selected.len() }
551
552 #[expect(clippy::indexing_slicing, reason = "the branch proves the item index is in bounds")]
554 pub fn weight(&self, item: usize) -> Option<u64> {
555 if item < self.inner.distribution.len() { Some(self.inner.distribution[item]) } else { None }
556 }
557
558 pub fn contains(&self, item: usize) -> bool { self.inner.contains_exec(item) }
560
561 pub fn sample(&mut self, item: usize) -> (result: Result<(), SamplerError>) {
563 proof { use_type_invariant(&*self); }
564 if item >= self.inner.num_items { return Err(SamplerError::ItemOutOfRange); }
565 if self.inner.selected.len() >= self.inner.sample_size { return Err(SamplerError::SampleFull); }
566 if self.inner.distribution[item] == 0 { return Err(SamplerError::OutsideSupport); }
567 if self.inner.contains_exec(item) { return Err(SamplerError::AlreadySelected); }
568 let mut carrier = sampler_sentinel();
569 core::mem::swap(&mut self.inner, &mut carrier);
570 carrier.sample(item);
571 core::mem::swap(&mut self.inner, &mut carrier);
572 Ok(())
573 }
574
575 #[must_use]
577 pub fn zero(&mut self, item: usize) -> (accepted: bool) {
578 proof { use_type_invariant(&*self); }
579 let mut carrier = sampler_sentinel();
580 core::mem::swap(&mut self.inner, &mut carrier);
581 let accepted = carrier.zero(item);
582 core::mem::swap(&mut self.inner, &mut carrier);
583 accepted
584 }
585
586 pub fn draw_weighted(&mut self, item: usize, entropy: u64) -> (result: Result<bool, SamplerError>) {
588 proof { use_type_invariant(&*self); }
589 if item >= self.inner.num_items { return Err(SamplerError::ItemOutOfRange); }
590 let mut carrier = sampler_sentinel();
591 core::mem::swap(&mut self.inner, &mut carrier);
592 let accepted = carrier.draw_weighted(item, entropy);
593 core::mem::swap(&mut self.inner, &mut carrier);
594 Ok(accepted)
595 }
596
597 pub fn draw_uniform(&mut self, item: usize) -> (result: Result<bool, SamplerError>) {
599 proof { use_type_invariant(&*self); }
600 if item >= self.inner.num_items { return Err(SamplerError::ItemOutOfRange); }
601 let mut carrier = sampler_sentinel();
602 core::mem::swap(&mut self.inner, &mut carrier);
603 let accepted = carrier.draw_uniform(item);
604 core::mem::swap(&mut self.inner, &mut carrier);
605 Ok(accepted)
606 }
607}
608
609#[derive(Clone, Copy, Debug, Eq, PartialEq)]
611#[non_exhaustive]
612pub enum SignalBuildError {
613 InitialValueOutOfRange,
615}
616
617#[derive(Clone, Copy, Debug, Eq, PartialEq)]
619#[non_exhaustive]
620pub enum SignalError {
621 ValueOutOfRange,
623 ListenerOutOfRange,
625 ListenerNotPending,
627}
628
629pub struct Signal {
631 inner: SignalCarrier,
632}
633
634impl Signal {
635 #[verifier::type_invariant]
636 closed spec fn well_formed(&self) -> bool {
637 self.inner.type_invariant()
638 && self.inner.pending_notified_disjointness()
639 && self.inner.notification_provenance()
640 }
641
642 pub fn new(initial_value: u64, num_values: u64, num_listeners: usize)
644 -> (result: Result<Self, SignalBuildError>) {
645 if initial_value >= num_values { return Err(SignalBuildError::InitialValueOutOfRange); }
646 Ok(Self { inner: SignalCarrier::new(initial_value, num_values, num_listeners) })
647 }
648
649 pub fn value(&self) -> u64 { self.inner.current_value }
651
652 pub fn listener_count(&self) -> usize { self.inner.num_listeners }
654
655 pub fn change_observed(&self) -> bool { self.inner.change_observed }
657
658 pub fn is_pending(&self, listener: usize) -> Option<bool> {
660 proof { use_type_invariant(&*self); }
661 if listener < self.inner.num_listeners { Some(self.inner.is_pending(listener)) } else { None }
662 }
663
664 pub fn is_notified(&self, listener: usize) -> Option<bool> {
666 proof { use_type_invariant(&*self); }
667 if listener < self.inner.num_listeners { Some(self.inner.is_notified(listener)) } else { None }
668 }
669
670 pub fn set_value(&mut self, value: u64) -> (result: Result<bool, SignalError>) {
672 proof { use_type_invariant(&*self); }
673 if value >= self.inner.num_values { return Err(SignalError::ValueOutOfRange); }
674 let mut carrier = signal_sentinel();
675 core::mem::swap(&mut self.inner, &mut carrier);
676 let changed = carrier.set_value(value);
677 core::mem::swap(&mut self.inner, &mut carrier);
678 Ok(changed)
679 }
680
681 pub fn notify(&mut self, listener: usize) -> (result: Result<(), SignalError>) {
683 proof { use_type_invariant(&*self); }
684 if listener >= self.inner.num_listeners { return Err(SignalError::ListenerOutOfRange); }
685 if !self.inner.is_pending(listener) { return Err(SignalError::ListenerNotPending); }
686 let mut carrier = signal_sentinel();
687 core::mem::swap(&mut self.inner, &mut carrier);
688 carrier.notify_listener(listener);
689 core::mem::swap(&mut self.inner, &mut carrier);
690 Ok(())
691 }
692}
693
694#[derive(Clone, Copy, Debug, Eq, PartialEq)]
696#[non_exhaustive]
697pub enum TraversalBuildError {
698 NoNodes,
700 RootOutOfRange,
702}
703
704#[derive(Clone, Copy, Debug, Eq, PartialEq)]
706#[non_exhaustive]
707pub enum TraversalError {
708 NodeOutOfRange,
710 NodeNotQueued,
712 NodeAlreadyVisited,
714 QueueNotEmpty,
716}
717
718pub struct TraversalEngine {
720 inner: TraversalEngineCarrier,
721}
722
723impl TraversalEngine {
724 #[verifier::type_invariant]
725 closed spec fn well_formed(&self) -> bool {
726 self.inner.type_invariant()
727 && self.inner.budget_invariant()
728 && self.inner.accepted_subset_visited()
729 && self.inner.root < self.inner.num_nodes
730 }
731
732 pub fn new(num_nodes: usize, root: usize, budget: u64)
734 -> (result: Result<Self, TraversalBuildError>) {
735 if num_nodes == 0 { return Err(TraversalBuildError::NoNodes); }
736 if root >= num_nodes { return Err(TraversalBuildError::RootOutOfRange); }
737 Ok(Self { inner: TraversalEngineCarrier::new(num_nodes, root, budget) })
738 }
739
740 pub fn num_nodes(&self) -> usize { self.inner.num_nodes }
742
743 pub fn root(&self) -> usize { self.inner.root }
745
746 pub fn budget_remaining(&self) -> u64 { self.inner.budget_remaining }
748
749 pub fn queued_len(&self) -> usize { self.inner.queue.len() }
751
752 pub fn visited_len(&self) -> usize { self.inner.visited.len() }
754
755 pub fn accepted_len(&self) -> usize { self.inner.accepted.len() }
757
758 pub fn is_queued(&self, node: usize) -> bool { self.inner.queue_contains(node) }
760
761 pub fn is_visited(&self, node: usize) -> bool { self.inner.visited_contains(node) }
763
764 pub fn is_accepted(&self, node: usize) -> bool { self.inner.accepted_contains(node) }
766
767 pub fn visit(&mut self, node: usize) -> (result: Result<(), TraversalError>) {
769 proof { use_type_invariant(&*self); }
770 if node >= self.inner.num_nodes { return Err(TraversalError::NodeOutOfRange); }
771 if !self.inner.queue_contains(node) { return Err(TraversalError::NodeNotQueued); }
772 if self.inner.visited_contains(node) { return Err(TraversalError::NodeAlreadyVisited); }
773 let mut carrier = traversal_engine_sentinel();
774 core::mem::swap(&mut self.inner, &mut carrier);
775 carrier.visit_node(node);
776 core::mem::swap(&mut self.inner, &mut carrier);
777 Ok(())
778 }
779
780 pub fn skip(&mut self, node: usize) -> (result: Result<(), TraversalError>) {
782 proof { use_type_invariant(&*self); }
783 if node >= self.inner.num_nodes { return Err(TraversalError::NodeOutOfRange); }
784 if !self.inner.queue_contains(node) { return Err(TraversalError::NodeNotQueued); }
785 let mut carrier = traversal_engine_sentinel();
786 core::mem::swap(&mut self.inner, &mut carrier);
787 carrier.skip(node);
788 core::mem::swap(&mut self.inner, &mut carrier);
789 Ok(())
790 }
791
792 pub fn terminate(&mut self) -> (result: Result<(), TraversalError>) {
794 proof { use_type_invariant(&*self); }
795 if !self.inner.queue.is_empty() { return Err(TraversalError::QueueNotEmpty); }
796 let mut carrier = traversal_engine_sentinel();
797 core::mem::swap(&mut self.inner, &mut carrier);
798 carrier.terminate();
799 core::mem::swap(&mut self.inner, &mut carrier);
800 Ok(())
801 }
802}
803
804proof fn lemma_u64_domain_fits_64(value: u64)
805 ensures value as int <= crate::compositions::bisection::pow2(64),
806{
807 assert(crate::compositions::bisection::pow2(64) == 18_446_744_073_709_551_616int) by (compute);
808}
809
810fn allocation_snapshot_sentinel() -> (carrier: AllocationSnapshotCarrier)
811 ensures carrier.type_invariant(), carrier.budget_consistency(),
812{ AllocationSnapshotCarrier::new(0, 0) }
813
814fn federated_budget_sentinel() -> (carrier: FederatedBudgetCarrier)
815 ensures carrier.inv(),
816{ FederatedBudgetCarrier::new(0, 0) }
817
818fn bisection_sentinel() -> (carrier: BisectionCarrier)
819 ensures carrier.invariant(),
820{
821 proof {
822 assert(crate::compositions::bisection::pow2(1) == 2) by (compute);
823 }
824 BisectionCarrier::new(0, 2, 1, 2, 1)
825}
826
827fn equivalence_class_sentinel() -> (carrier: EquivalenceClassCarrier)
828 ensures carrier.inv(),
829{ EquivalenceClassCarrier::new(0, 0) }
830
831fn rate_limit_sentinel() -> (carrier: RateLimitCarrier)
832 ensures carrier.type_invariant(), carrier.window_start_not_future(),
833{ RateLimitCarrier::new(1, 1, 0) }
834
835fn reduction_sentinel() -> (carrier: ReductionCarrier)
836 ensures carrier.partition(), carrier.aggregate(), carrier.bounded(),
837{
838 let values: Vec<u64> = Vec::new();
839 ReductionCarrier::new(values)
840}
841
842fn relationship_graph_sentinel() -> (carrier: RelationshipGraphCarrier)
843 ensures carrier.inv(),
844{ RelationshipGraphCarrier::new(0, 0) }
845
846fn sampler_sentinel() -> (carrier: SamplerCarrier)
847 ensures carrier.inv(),
848{
849 let distribution: Vec<u64> = Vec::new();
850 SamplerCarrier::new(distribution, 0)
851}
852
853fn signal_sentinel() -> (carrier: SignalCarrier)
854 ensures
855 carrier.type_invariant(),
856 carrier.pending_notified_disjointness(),
857 carrier.notification_provenance(),
858{ SignalCarrier::new(0, 1, 0) }
859
860fn traversal_engine_sentinel() -> (carrier: TraversalEngineCarrier)
861 ensures
862 carrier.type_invariant(),
863 carrier.budget_invariant(),
864 carrier.accepted_subset_visited(),
865 carrier.root < carrier.num_nodes,
866{ TraversalEngineCarrier::new(1, 0, 0) }
867
868}
869
870macro_rules! impl_error {
871 ($type:ty, { $($variant:path => $message:literal),+ $(,)? }) => {
872 impl core::fmt::Display for $type {
873 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
874 formatter.write_str(match self { $($variant => $message),+ })
875 }
876 }
877 impl std::error::Error for $type {}
878 };
879}
880
881macro_rules! impl_observational_debug {
882 ($type:ty, $name:literal, $($field:literal => $method:ident),+ $(,)?) => {
883 impl core::fmt::Debug for $type {
884 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
885 let mut state = formatter.debug_struct($name);
886 $(state.field($field, &self.$method());)+
887 state.finish()
888 }
889 }
890 };
891}
892
893impl_observational_debug!(AllocationSnapshot, "AllocationSnapshot",
894 "capacity" => capacity,
895 "num_nodes" => num_nodes,
896 "total_cost" => total_cost,
897 "budget_remaining" => budget_remaining,
898 "len" => len,
899);
900impl_observational_debug!(FederatedBudget, "FederatedBudget",
901 "master_capacity" => master_capacity,
902 "master_allocated" => master_allocated,
903 "len" => len,
904);
905impl_observational_debug!(Bisection, "Bisection",
906 "lower" => lower,
907 "upper" => upper,
908 "threshold" => threshold,
909 "probes_taken" => probes_taken,
910 "max_probes" => max_probes,
911 "converged" => is_converged,
912);
913impl_observational_debug!(EquivalenceClass, "EquivalenceClass",
914 "len" => len,
915 "unions_performed" => unions_performed,
916 "max_unions" => max_unions,
917);
918impl_observational_debug!(RateLimit, "RateLimit",
919 "max_per_window" => max_per_window,
920 "window_duration" => window_duration,
921 "count" => count,
922 "clock" => clock,
923 "window_start" => window_start,
924);
925impl_observational_debug!(Reduction, "Reduction",
926 "result" => result,
927 "processed_len" => processed_len,
928 "remaining_len" => remaining_len,
929 "complete" => is_complete,
930);
931impl_observational_debug!(RelationshipGraph, "RelationshipGraph",
932 "num_nodes" => num_nodes,
933 "max_weight" => max_weight,
934 "edge_count" => edge_count,
935);
936impl_observational_debug!(Sampler, "Sampler",
937 "len" => len,
938 "sample_size" => sample_size,
939 "selected_len" => selected_len,
940);
941impl_observational_debug!(Signal, "Signal",
942 "value" => value,
943 "listener_count" => listener_count,
944 "change_observed" => change_observed,
945);
946impl_observational_debug!(TraversalEngine, "TraversalEngine",
947 "num_nodes" => num_nodes,
948 "root" => root,
949 "budget_remaining" => budget_remaining,
950 "queued_len" => queued_len,
951 "visited_len" => visited_len,
952 "accepted_len" => accepted_len,
953);
954
955impl_error!(AllocationSnapshotError, {
956 Self::NodeOutOfRange => "node is outside the snapshot universe",
957 Self::NodeAlreadyAccepted => "node is already accepted",
958 Self::ZeroCost => "accepted node cost must be positive",
959 Self::InsufficientBudget => "node cost exceeds the remaining budget",
960});
961impl_error!(BisectionBuildError, {
962 Self::DomainTooSmall => "bisection domain must contain at least two points",
963 Self::ThresholdOutOfRange => "bisection threshold is outside the domain",
964});
965impl_error!(BisectionError, { Self::AlreadyConverged => "bisection is already converged" });
966impl_error!(EquivalenceClassError, { Self::ElementOutOfRange => "element is outside the partition" });
967impl_error!(RateLimitBuildError, { Self::ZeroLimit => "rate limit must admit at least one operation" });
968impl_error!(RateLimitError, { Self::ClockExhausted => "rate-limit logical clock is exhausted" });
969impl_error!(ReductionBuildError, {
970 Self::TooManyItems => "reduction input exceeds the verified item ceiling",
971 Self::ValueOutOfRange => "reduction input exceeds the verified value ceiling",
972});
973impl_error!(ReductionError, { Self::Complete => "reduction is already complete" });
974impl_error!(RelationshipGraphError, {
975 Self::NodeOutOfRange => "graph node is outside the configured universe",
976 Self::WeightOutOfRange => "edge weight exceeds the configured maximum",
977 Self::SelfLoop => "relationship graph does not admit self-loops",
978});
979impl_error!(SamplerError, {
980 Self::ItemOutOfRange => "sample item is outside the distribution",
981 Self::SampleFull => "bounded sample is full",
982 Self::OutsideSupport => "sample item has zero support weight",
983 Self::AlreadySelected => "sample item is already selected",
984});
985impl_error!(SignalBuildError, { Self::InitialValueOutOfRange => "initial signal value is outside its universe" });
986impl_error!(SignalError, {
987 Self::ValueOutOfRange => "signal value is outside its universe",
988 Self::ListenerOutOfRange => "listener is outside the signal universe",
989 Self::ListenerNotPending => "listener has no pending notification",
990});
991impl_error!(TraversalBuildError, {
992 Self::NoNodes => "traversal requires at least one node",
993 Self::RootOutOfRange => "traversal root is outside the node universe",
994});
995impl_error!(TraversalError, {
996 Self::NodeOutOfRange => "traversal node is outside the configured universe",
997 Self::NodeNotQueued => "traversal node is not queued",
998 Self::NodeAlreadyVisited => "traversal node was already visited",
999 Self::QueueNotEmpty => "traversal queue is not empty",
1000});