1use crate::connectives::cursor::Cursor as CursorCarrier;
8use crate::primitives::actuation_pass::ActuationPass as ActuationPassCarrier;
9use crate::primitives::audit_sink::AuditSink as AuditSinkCarrier;
10use crate::primitives::backtracking_traversal::BacktrackingTraversal as BacktrackingTraversalCarrier;
11use crate::primitives::budget::Budget as BudgetCarrier;
12use crate::primitives::competitive_selection::{
13 CompetitiveSelectionHard as CompetitiveSelectionHardCarrier,
14 CompetitiveSelectionHardExclusive as CompetitiveSelectionHardExclusiveCarrier,
15 CompetitiveSelectionRanked as CompetitiveSelectionRankedCarrier,
16 CompetitiveSelectionSoft as CompetitiveSelectionSoftCarrier,
17};
18use crate::primitives::convergence_governor_phase_aware::ConvergenceGovernorPhaseAware as ConvergenceGovernorCarrier;
19use crate::primitives::propagation_pass::PropagationPass as PropagationPassCarrier;
20use crate::primitives::quality_hierarchy::QualityHierarchy as QualityHierarchyCarrier;
21use crate::primitives::resource_registry::ResourceRegistry as RegistryCarrier;
22use vstd::prelude::*;
23
24pub use crate::primitives::convergence_governor_phase_aware::{
25 GovState as ConvergenceState, Phase as ConvergencePhase,
26};
27pub use crate::primitives::propagation_pass::Round as PropagationRound;
28
29verus! {
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33#[non_exhaustive]
34pub enum BudgetError {
35 AmountExceedsReservation,
37 AmountExceedsAllocation,
39 AmountExceedsPendingEviction,
41}
42
43pub struct Budget {
45 inner: BudgetCarrier,
46}
47
48impl Budget {
49 #[verifier::type_invariant]
50 closed spec fn well_formed(&self) -> bool {
51 self.inner.safety_invariant()
52 }
53
54 pub fn new(capacity: u64) -> (budget: Self) {
56 let inner = BudgetCarrier::new(capacity);
57 Self { inner }
58 }
59
60 pub fn capacity(&self) -> u64 {
62 self.inner.capacity
63 }
64
65 pub fn allocated(&self) -> u64 {
67 self.inner.allocated
68 }
69
70 pub fn reserved(&self) -> u64 {
72 self.inner.reserved
73 }
74
75 pub fn pending_eviction(&self) -> u64 {
77 self.inner.pending_eviction
78 }
79
80 pub fn available(&self) -> (available: u64) {
82 proof { use_type_invariant(&*self); }
83 self.inner.available()
84 }
85
86 #[must_use]
88 pub fn try_allocate(&mut self, amount: u64) -> (accepted: bool) {
89 proof { use_type_invariant(&*self); }
90 let mut carrier = budget_sentinel();
91 core::mem::swap(&mut self.inner, &mut carrier);
92 let accepted = carrier.try_allocate(amount);
93 core::mem::swap(&mut self.inner, &mut carrier);
94 accepted
95 }
96
97 #[must_use]
99 pub fn try_reserve(&mut self, amount: u64) -> (accepted: bool) {
100 proof { use_type_invariant(&*self); }
101 let mut carrier = budget_sentinel();
102 core::mem::swap(&mut self.inner, &mut carrier);
103 let accepted = carrier.reserve(amount);
104 core::mem::swap(&mut self.inner, &mut carrier);
105 accepted
106 }
107
108 pub fn commit_reservation(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
110 proof { use_type_invariant(&*self); }
111 if amount <= self.inner.reserved {
112 let mut carrier = budget_sentinel();
113 core::mem::swap(&mut self.inner, &mut carrier);
114 carrier.commit_reservation(amount);
115 core::mem::swap(&mut self.inner, &mut carrier);
116 Ok(())
117 } else {
118 Err(BudgetError::AmountExceedsReservation)
119 }
120 }
121
122 pub fn release(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
124 proof { use_type_invariant(&*self); }
125 if amount <= self.inner.allocated {
126 let mut carrier = budget_sentinel();
127 core::mem::swap(&mut self.inner, &mut carrier);
128 carrier.release(amount);
129 core::mem::swap(&mut self.inner, &mut carrier);
130 Ok(())
131 } else {
132 Err(BudgetError::AmountExceedsAllocation)
133 }
134 }
135
136 pub fn mark_eviction(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
138 proof { use_type_invariant(&*self); }
139 if amount <= self.inner.allocated {
140 let mut carrier = budget_sentinel();
141 core::mem::swap(&mut self.inner, &mut carrier);
142 carrier.mark_eviction(amount);
143 core::mem::swap(&mut self.inner, &mut carrier);
144 Ok(())
145 } else {
146 Err(BudgetError::AmountExceedsAllocation)
147 }
148 }
149
150 pub fn complete_eviction(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
152 proof { use_type_invariant(&*self); }
153 if amount <= self.inner.pending_eviction {
154 let mut carrier = budget_sentinel();
155 core::mem::swap(&mut self.inner, &mut carrier);
156 carrier.complete_eviction(amount);
157 core::mem::swap(&mut self.inner, &mut carrier);
158 Ok(())
159 } else {
160 Err(BudgetError::AmountExceedsPendingEviction)
161 }
162 }
163}
164
165pub struct ResourceRegistry {
167 inner: RegistryCarrier,
168}
169
170impl ResourceRegistry {
171 #[verifier::type_invariant]
172 closed spec fn well_formed(&self) -> bool {
173 self.inner.unique_mapping()
174 }
175
176 pub fn new() -> (registry: Self) {
178 let inner = RegistryCarrier::new();
179 Self { inner }
180 }
181
182 pub fn len(&self) -> usize {
184 self.inner.entries.len()
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.inner.entries.is_empty()
190 }
191
192 pub fn get(&self, key: u64) -> (value: Option<u64>) {
194 proof { use_type_invariant(&*self); }
195 self.inner.lookup(key)
196 }
197
198 pub fn insert(&mut self, key: u64, value: u64) -> (previous: Option<u64>) {
200 proof { use_type_invariant(&*self); }
201 let previous = self.inner.lookup(key);
202 let mut carrier = registry_sentinel();
203 core::mem::swap(&mut self.inner, &mut carrier);
204 carrier.register(key, value);
205 core::mem::swap(&mut self.inner, &mut carrier);
206 previous
207 }
208
209 pub fn remove(&mut self, key: u64) -> (previous: Option<u64>) {
211 proof { use_type_invariant(&*self); }
212 let previous = self.inner.lookup(key);
213 match previous {
214 Some(value) => {
215 let mut carrier = registry_sentinel();
216 core::mem::swap(&mut self.inner, &mut carrier);
217 carrier.deregister(key);
218 core::mem::swap(&mut self.inner, &mut carrier);
219 Some(value)
220 },
221 None => None,
222 }
223 }
224
225 #[expect(clippy::indexing_slicing, reason = "the branch proves the registry index is in bounds")]
227 pub fn entry(&self, index: usize) -> Option<(u64, u64)> {
228 if index < self.inner.entries.len() {
229 Some(self.inner.entries[index])
230 } else {
231 None
232 }
233 }
234}
235
236#[derive(Clone, Copy, Debug, Eq, PartialEq)]
238pub struct AuditRecord {
239 pub operation: u64,
241 pub previous_hash: u64,
243 pub hash: u64,
245}
246
247pub struct AuditSink {
249 inner: AuditSinkCarrier,
250}
251
252impl AuditSink {
253 #[verifier::type_invariant]
254 closed spec fn well_formed(&self) -> bool {
255 self.inner.inv()
256 }
257
258 pub fn new(capacity: usize) -> (sink: Self) {
260 let inner = AuditSinkCarrier::new(capacity);
261 Self { inner }
262 }
263
264 pub fn capacity(&self) -> usize {
266 self.inner.max_log_len
267 }
268
269 pub fn len(&self) -> usize {
271 self.inner.log.len()
272 }
273
274 pub fn is_empty(&self) -> bool {
276 self.inner.log.is_empty()
277 }
278
279 pub fn last_hash(&self) -> u64 {
281 self.inner.last_hash
282 }
283
284 #[must_use]
286 pub fn try_record(&mut self, operation: u64) -> (accepted: bool) {
287 proof { use_type_invariant(&*self); }
288 let mut carrier = audit_sentinel();
289 core::mem::swap(&mut self.inner, &mut carrier);
290 let accepted = carrier.record(operation);
291 core::mem::swap(&mut self.inner, &mut carrier);
292 accepted
293 }
294
295 pub fn validate(&self) -> (valid: bool) {
297 proof { use_type_invariant(&*self); }
298 self.inner.validate()
299 }
300
301 #[expect(clippy::indexing_slicing, reason = "the branch proves the audit index is in bounds")]
303 pub fn record(&self, index: usize) -> Option<AuditRecord> {
304 if index < self.inner.log.len() {
305 let entry = &self.inner.log[index];
306 Some(AuditRecord {
307 operation: entry.operation,
308 previous_hash: entry.prev_hash,
309 hash: entry.hash,
310 })
311 } else {
312 None
313 }
314 }
315}
316
317#[derive(Clone, Copy, Debug, Eq, PartialEq)]
319#[non_exhaustive]
320pub enum CursorError {
321 Regression,
323}
324
325pub struct Cursor {
327 inner: CursorCarrier,
328}
329
330impl Cursor {
331 pub fn new(position: usize) -> (cursor: Self) {
333 Self { inner: CursorCarrier::new(position) }
334 }
335
336 pub fn position(&self) -> usize {
338 self.inner.position
339 }
340
341 pub fn advance_to(&mut self, position: usize) -> (result: Result<(), CursorError>) {
343 if position < self.inner.position {
344 return Err(CursorError::Regression);
345 }
346 self.inner.advance_to(position);
347 Ok(())
348 }
349}
350
351#[derive(Clone, Copy, Debug, Eq, PartialEq)]
353#[non_exhaustive]
354pub enum PropagationBuildError {
355 InitialValueOutOfRange,
357 EdgeEndpointOutOfRange,
359}
360
361#[derive(Clone, Copy, Debug, Eq, PartialEq)]
363#[non_exhaustive]
364pub enum PropagationError {
365 NodeOutOfRange,
367 RoundAlreadyRunning,
369 RoundNotRunning,
371 NodeAlreadyUpdated,
373 RoundIncomplete,
375 PassTerminated,
377 PassStillRunning,
379}
380
381pub struct PropagationPass {
383 inner: PropagationPassCarrier,
384}
385
386impl PropagationPass {
387 #[verifier::type_invariant]
388 closed spec fn well_formed(&self) -> bool {
389 self.inner.inv()
390 }
391
392 pub fn new(
394 max_iterations: u64,
395 max_value: u64,
396 edges: Vec<(usize, usize)>,
397 initial_values: Vec<u64>,
398 ) -> (result: Result<Self, PropagationBuildError>) {
399 if !values_within_max(&initial_values, max_value) {
400 return Err(PropagationBuildError::InitialValueOutOfRange);
401 }
402 let num_nodes = initial_values.len();
403 if !edges_within_nodes(&edges, num_nodes) {
404 return Err(PropagationBuildError::EdgeEndpointOutOfRange);
405 }
406 let inner = PropagationPassCarrier::new(
407 num_nodes,
408 max_iterations,
409 max_value,
410 edges,
411 initial_values,
412 );
413 Ok(Self { inner })
414 }
415
416 pub fn num_nodes(&self) -> usize {
418 self.inner.num_nodes
419 }
420
421 pub fn max_iterations(&self) -> u64 {
423 self.inner.max_iterations
424 }
425
426 pub fn max_value(&self) -> u64 {
428 self.inner.max_value
429 }
430
431 pub fn iteration(&self) -> u64 {
433 self.inner.iteration
434 }
435
436 pub fn round(&self) -> PropagationRound {
438 self.inner.round
439 }
440
441 pub fn changed(&self) -> bool {
443 self.inner.changed
444 }
445
446 #[expect(clippy::indexing_slicing, reason = "the branch proves the node index is in bounds")]
448 pub fn value(&self, node: usize) -> Option<u64> {
449 if node < self.inner.values.len() {
450 Some(self.inner.values[node])
451 } else {
452 None
453 }
454 }
455
456 #[expect(clippy::indexing_slicing, reason = "the branch proves the snapshot index is in bounds")]
458 pub fn snapshot_value(&self, node: usize) -> Option<u64> {
459 if node < self.inner.snapshot.len() {
460 Some(self.inner.snapshot[node])
461 } else {
462 None
463 }
464 }
465
466 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
468 pub fn node_updated(&self, node: usize) -> Option<bool> {
469 if node < self.inner.updated.len() {
470 Some(self.inner.updated[node])
471 } else {
472 None
473 }
474 }
475
476 pub fn start_round(&mut self) -> (result: Result<(), PropagationError>) {
478 proof { use_type_invariant(&*self); }
479 match self.inner.round {
480 PropagationRound::Running => {
481 return Err(PropagationError::RoundAlreadyRunning);
482 },
483 PropagationRound::Idle => {},
484 }
485 if !self.inner.changed || self.inner.iteration >= self.inner.max_iterations {
486 return Err(PropagationError::PassTerminated);
487 }
488 let mut carrier = propagation_sentinel();
489 core::mem::swap(&mut self.inner, &mut carrier);
490 carrier.start_round();
491 core::mem::swap(&mut self.inner, &mut carrier);
492 Ok(())
493 }
494
495 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
497 pub fn update_node(&mut self, node: usize) -> (result: Result<(), PropagationError>) {
498 proof { use_type_invariant(&*self); }
499 match self.inner.round {
500 PropagationRound::Idle => {
501 return Err(PropagationError::RoundNotRunning);
502 },
503 PropagationRound::Running => {},
504 }
505 if node >= self.inner.num_nodes {
506 return Err(PropagationError::NodeOutOfRange);
507 }
508 if self.inner.updated[node] {
509 return Err(PropagationError::NodeAlreadyUpdated);
510 }
511 let mut carrier = propagation_sentinel();
512 core::mem::swap(&mut self.inner, &mut carrier);
513 carrier.update_node(node);
514 core::mem::swap(&mut self.inner, &mut carrier);
515 Ok(())
516 }
517
518 pub fn end_round(&mut self) -> (result: Result<(), PropagationError>) {
520 proof { use_type_invariant(&*self); }
521 match self.inner.round {
522 PropagationRound::Idle => {
523 return Err(PropagationError::RoundNotRunning);
524 },
525 PropagationRound::Running => {},
526 }
527 if !self.inner.all_nodes_updated() {
528 return Err(PropagationError::RoundIncomplete);
529 }
530 let mut carrier = propagation_sentinel();
531 core::mem::swap(&mut self.inner, &mut carrier);
532 carrier.end_round();
533 core::mem::swap(&mut self.inner, &mut carrier);
534 Ok(())
535 }
536
537 pub fn terminate(&mut self) -> (result: Result<(), PropagationError>) {
539 proof { use_type_invariant(&*self); }
540 match self.inner.round {
541 PropagationRound::Running => {
542 return Err(PropagationError::RoundAlreadyRunning);
543 },
544 PropagationRound::Idle => {},
545 }
546 if self.inner.changed && self.inner.iteration != self.inner.max_iterations {
547 return Err(PropagationError::PassStillRunning);
548 }
549 let mut carrier = propagation_sentinel();
550 core::mem::swap(&mut self.inner, &mut carrier);
551 carrier.terminate();
552 core::mem::swap(&mut self.inner, &mut carrier);
553 Ok(())
554 }
555}
556
557#[derive(Clone, Copy, Debug, Eq, PartialEq)]
559#[non_exhaustive]
560pub enum ActuationError {
561 SeatOutOfRange,
563 PassComplete,
565 SeatAlreadyAllocated,
567 SeatUnallocated,
569 SeatAlreadyActuated,
571 PassIncomplete,
573}
574
575pub struct ActuationPass {
577 inner: ActuationPassCarrier,
578}
579
580impl ActuationPass {
581 #[verifier::type_invariant]
582 closed spec fn well_formed(&self) -> bool {
583 self.inner.invariant()
584 }
585
586 pub fn new(allocation: Vec<Option<u64>>) -> (pass: Self) {
588 let num_seats = allocation.len();
589 let inner = ActuationPassCarrier::new(allocation, num_seats);
590 Self { inner }
591 }
592
593 pub fn len(&self) -> usize {
595 self.inner.num_seats
596 }
597
598 pub fn is_empty(&self) -> bool {
600 self.inner.num_seats == 0
601 }
602
603 pub fn is_complete(&self) -> bool {
605 self.inner.complete
606 }
607
608 #[expect(clippy::indexing_slicing, reason = "the branch proves the allocation index is in bounds")]
610 pub fn allocation(&self, seat: usize) -> Option<Option<u64>> {
611 if seat < self.inner.allocation.len() {
612 Some(self.inner.allocation[seat])
613 } else {
614 None
615 }
616 }
617
618 #[expect(clippy::indexing_slicing, reason = "the branch proves the effect index is in bounds")]
620 pub fn effect(&self, seat: usize) -> Option<Option<u64>> {
621 if seat < self.inner.effects.len() {
622 Some(self.inner.effects[seat])
623 } else {
624 None
625 }
626 }
627
628 pub fn allocate(&mut self, seat: usize, resource: u64) -> (result: Result<(), ActuationError>) {
630 proof { use_type_invariant(&*self); }
631 if seat >= self.inner.num_seats {
632 return Err(ActuationError::SeatOutOfRange);
633 }
634 if self.inner.complete {
635 return Err(ActuationError::PassComplete);
636 }
637 if !self.inner.can_allocate(seat) {
638 return Err(ActuationError::SeatAlreadyAllocated);
639 }
640 let mut carrier = actuation_sentinel();
641 core::mem::swap(&mut self.inner, &mut carrier);
642 carrier.allocate(seat, resource);
643 core::mem::swap(&mut self.inner, &mut carrier);
644 Ok(())
645 }
646
647 pub fn deallocate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
649 proof { use_type_invariant(&*self); }
650 if seat >= self.inner.num_seats {
651 return Err(ActuationError::SeatOutOfRange);
652 }
653 if self.inner.complete {
654 return Err(ActuationError::PassComplete);
655 }
656 if !self.inner.is_allocated(seat) {
657 return Err(ActuationError::SeatUnallocated);
658 }
659 if !self.inner.can_deallocate(seat) {
660 return Err(ActuationError::SeatAlreadyActuated);
661 }
662 let mut carrier = actuation_sentinel();
663 core::mem::swap(&mut self.inner, &mut carrier);
664 carrier.deallocate(seat);
665 core::mem::swap(&mut self.inner, &mut carrier);
666 Ok(())
667 }
668
669 pub fn actuate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
671 proof { use_type_invariant(&*self); }
672 if seat >= self.inner.num_seats {
673 return Err(ActuationError::SeatOutOfRange);
674 }
675 if self.inner.complete {
676 return Err(ActuationError::PassComplete);
677 }
678 if !self.inner.is_allocated(seat) {
679 return Err(ActuationError::SeatUnallocated);
680 }
681 if !self.inner.can_actuate(seat) {
682 return Err(ActuationError::SeatAlreadyActuated);
683 }
684 let mut carrier = actuation_sentinel();
685 core::mem::swap(&mut self.inner, &mut carrier);
686 carrier.actuate(seat);
687 core::mem::swap(&mut self.inner, &mut carrier);
688 Ok(())
689 }
690
691 pub fn ready_to_finish(&self) -> (ready: bool) {
693 proof { use_type_invariant(&*self); }
694 self.inner.ready_to_finish_exec()
695 }
696
697 pub fn finish(&mut self) -> (result: Result<(), ActuationError>) {
699 proof { use_type_invariant(&*self); }
700 if self.inner.complete {
701 return Err(ActuationError::PassComplete);
702 }
703 if !self.inner.ready_to_finish_exec() {
704 return Err(ActuationError::PassIncomplete);
705 }
706 let mut carrier = actuation_sentinel();
707 core::mem::swap(&mut self.inner, &mut carrier);
708 carrier.finish();
709 core::mem::swap(&mut self.inner, &mut carrier);
710 Ok(())
711 }
712}
713
714#[derive(Clone, Copy, Debug, Eq, PartialEq)]
716#[non_exhaustive]
717pub enum QualityHierarchyError {
718 NodeOutOfRange,
720 ParentOutOfRange,
722 ChildOutOfRange,
724 LevelOutOfRange,
726 CostOutOfRange,
728 NodeNotIsolated,
730 SelfEdge,
732 EdgeAlreadyExists,
734 ChildAlreadyParented,
736 LevelOrderViolation,
738 CostOrderViolation,
740}
741
742pub struct QualityHierarchy {
744 inner: QualityHierarchyCarrier,
745}
746
747impl QualityHierarchy {
748 #[verifier::type_invariant]
749 closed spec fn well_formed(&self) -> bool {
750 self.inner.type_invariant()
751 && self.inner.strict_level_descent()
752 && self.inner.parent_edge_agreement()
753 && self.inner.cost_monotonicity()
754 }
755
756 pub fn new(num_nodes: usize, max_level: u64) -> (hierarchy: Self) {
758 let inner = QualityHierarchyCarrier::new(num_nodes, max_level);
759 Self { inner }
760 }
761
762 pub fn len(&self) -> usize {
764 self.inner.num_nodes
765 }
766
767 pub fn is_empty(&self) -> bool {
769 self.inner.num_nodes == 0
770 }
771
772 pub fn max_level(&self) -> u64 {
774 self.inner.max_level
775 }
776
777 pub fn level(&self, node: usize) -> Option<u64> {
779 proof { use_type_invariant(&*self); }
780 if node < self.inner.num_nodes {
781 Some(self.inner.level_of(node))
782 } else {
783 None
784 }
785 }
786
787 pub fn cost(&self, node: usize) -> Option<u64> {
789 proof { use_type_invariant(&*self); }
790 if node < self.inner.num_nodes {
791 Some(self.inner.cost_of(node))
792 } else {
793 None
794 }
795 }
796
797 pub fn parent(&self, node: usize) -> Option<usize> {
799 proof { use_type_invariant(&*self); }
800 if node >= self.inner.num_nodes {
801 return None;
802 }
803 let parent = self.inner.parent_of(node);
804 if parent == self.inner.num_nodes {
805 None
806 } else {
807 Some(parent)
808 }
809 }
810
811 pub fn edge_count(&self) -> usize {
813 self.inner.edges.len()
814 }
815
816 #[expect(clippy::indexing_slicing, reason = "the branch proves the hierarchy edge index is in bounds")]
818 pub fn edge(&self, index: usize) -> Option<(usize, usize)> {
819 if index < self.inner.edges.len() {
820 Some(self.inner.edges[index])
821 } else {
822 None
823 }
824 }
825
826 pub fn set_node_properties(
828 &mut self,
829 node: usize,
830 level: u64,
831 cost: u64,
832 ) -> (result: Result<(), QualityHierarchyError>) {
833 proof { use_type_invariant(&*self); }
834 if node >= self.inner.num_nodes {
835 return Err(QualityHierarchyError::NodeOutOfRange);
836 }
837 if level > self.inner.max_level {
838 return Err(QualityHierarchyError::LevelOutOfRange);
839 }
840 if cost > self.inner.max_level {
841 return Err(QualityHierarchyError::CostOutOfRange);
842 }
843 if !self.inner.can_set_node_properties(node, level, cost) {
844 return Err(QualityHierarchyError::NodeNotIsolated);
845 }
846 let mut carrier = quality_hierarchy_sentinel();
847 core::mem::swap(&mut self.inner, &mut carrier);
848 carrier.set_node_properties(node, level, cost);
849 core::mem::swap(&mut self.inner, &mut carrier);
850 Ok(())
851 }
852
853 pub fn add_child(
855 &mut self,
856 parent: usize,
857 child: usize,
858 ) -> (result: Result<(), QualityHierarchyError>) {
859 proof { use_type_invariant(&*self); }
860 if parent >= self.inner.num_nodes {
861 return Err(QualityHierarchyError::ParentOutOfRange);
862 }
863 if child >= self.inner.num_nodes {
864 return Err(QualityHierarchyError::ChildOutOfRange);
865 }
866 if self.inner.can_add_child(parent, child) {
867 let mut carrier = quality_hierarchy_sentinel();
868 core::mem::swap(&mut self.inner, &mut carrier);
869 carrier.add_child(parent, child);
870 core::mem::swap(&mut self.inner, &mut carrier);
871 return Ok(());
872 }
873 if parent == child {
874 Err(QualityHierarchyError::SelfEdge)
875 } else if self.inner.has_edge(parent, child) {
876 Err(QualityHierarchyError::EdgeAlreadyExists)
877 } else if self.inner.parent_of(child) != self.inner.num_nodes {
878 Err(QualityHierarchyError::ChildAlreadyParented)
879 } else if self.inner.level_of(parent) <= self.inner.level_of(child) {
880 Err(QualityHierarchyError::LevelOrderViolation)
881 } else {
882 Err(QualityHierarchyError::CostOrderViolation)
883 }
884 }
885}
886
887#[derive(Clone, Copy, Debug, Eq, PartialEq)]
889#[non_exhaustive]
890pub enum BacktrackingBuildError {
891 InitialAuxOutOfRange,
893}
894
895#[derive(Clone, Copy, Debug, Eq, PartialEq)]
897#[non_exhaustive]
898pub enum BacktrackingError {
899 AtLeaf,
901 ChoiceOutOfRange,
903 DeltaOutOfRange,
905 NotLeaf,
907 AlreadyVisited,
909 AtRoot,
911}
912
913pub struct BacktrackingTraversal {
915 inner: BacktrackingTraversalCarrier,
916}
917
918impl BacktrackingTraversal {
919 #[verifier::type_invariant]
920 closed spec fn well_formed(&self) -> bool {
921 self.inner.inv()
922 }
923
924 pub fn new(
926 branch_factor: u64,
927 max_depth: usize,
928 initial_aux: u64,
929 ) -> (result: Result<Self, BacktrackingBuildError>) {
930 if initial_aux >= 3 {
931 return Err(BacktrackingBuildError::InitialAuxOutOfRange);
932 }
933 let inner = BacktrackingTraversalCarrier::new(branch_factor, max_depth, initial_aux);
934 Ok(Self { inner })
935 }
936
937 pub fn max_depth(&self) -> usize {
939 self.inner.max_depth
940 }
941
942 pub fn depth(&self) -> usize {
944 self.inner.path.len()
945 }
946
947 pub fn auxiliary(&self) -> u64 {
949 self.inner.aux
950 }
951
952 pub fn visited_count(&self) -> usize {
954 self.inner.visited.len()
955 }
956
957 pub fn is_leaf(&self) -> bool {
959 self.inner.is_leaf_exec()
960 }
961
962 #[expect(clippy::indexing_slicing, reason = "the branch proves the path index is in bounds")]
964 pub fn choice(&self, depth: usize) -> Option<u64> {
965 if depth < self.inner.path.len() {
966 Some(self.inner.path[depth])
967 } else {
968 None
969 }
970 }
971
972 pub fn descend(&mut self, choice: u64, delta: u64) -> (result: Result<(), BacktrackingError>) {
974 proof { use_type_invariant(&*self); }
975 if self.inner.is_leaf_exec() {
976 return Err(BacktrackingError::AtLeaf);
977 }
978 if choice < 1 || choice > self.inner.branch_factor {
979 return Err(BacktrackingError::ChoiceOutOfRange);
980 }
981 if delta < 1 || delta > 2 {
982 return Err(BacktrackingError::DeltaOutOfRange);
983 }
984 let mut carrier = backtracking_sentinel();
985 core::mem::swap(&mut self.inner, &mut carrier);
986 carrier.descend(choice, delta);
987 core::mem::swap(&mut self.inner, &mut carrier);
988 Ok(())
989 }
990
991 pub fn visit(&mut self) -> (result: Result<(), BacktrackingError>) {
993 proof { use_type_invariant(&*self); }
994 if !self.inner.is_leaf_exec() {
995 return Err(BacktrackingError::NotLeaf);
996 }
997 if !self.inner.can_visit() {
998 return Err(BacktrackingError::AlreadyVisited);
999 }
1000 let mut carrier = backtracking_sentinel();
1001 core::mem::swap(&mut self.inner, &mut carrier);
1002 carrier.visit();
1003 core::mem::swap(&mut self.inner, &mut carrier);
1004 Ok(())
1005 }
1006
1007 pub fn ascend(&mut self) -> (result: Result<(), BacktrackingError>) {
1009 proof { use_type_invariant(&*self); }
1010 if !self.inner.can_ascend() {
1011 return Err(BacktrackingError::AtRoot);
1012 }
1013 let mut carrier = backtracking_sentinel();
1014 core::mem::swap(&mut self.inner, &mut carrier);
1015 carrier.ascend();
1016 core::mem::swap(&mut self.inner, &mut carrier);
1017 Ok(())
1018 }
1019}
1020
1021#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1023#[non_exhaustive]
1024pub enum CompetitiveSelectionError {
1025 NoCandidates,
1027 CandidateOutOfRange,
1029 SeatOutOfRange,
1031 SeatAlreadyAllocated,
1033 NoCandidateAvailable,
1035 ScoreOutOfRange,
1037 ScoreCountMismatch,
1039 WeightTotalBelowReservedFloor,
1041 WeightTotalOutOfRange,
1043 MaxScoreOutOfRange,
1045 AllocationComplete,
1047}
1048
1049pub struct CompetitiveSelectionHard {
1051 inner: CompetitiveSelectionHardCarrier,
1052}
1053
1054impl CompetitiveSelectionHard {
1055 #[verifier::type_invariant]
1056 closed spec fn well_formed(&self) -> bool {
1057 self.inner.inv() && self.inner.scores.len() >= 1
1058 }
1059
1060 pub fn new(num_candidates: usize) -> (result: Result<Self, CompetitiveSelectionError>) {
1062 if num_candidates == 0 {
1063 return Err(CompetitiveSelectionError::NoCandidates);
1064 }
1065 let inner = CompetitiveSelectionHardCarrier::new(num_candidates);
1066 Ok(Self { inner })
1067 }
1068
1069 pub fn len(&self) -> usize {
1071 self.inner.scores.len()
1072 }
1073
1074 pub fn is_empty(&self) -> bool {
1076 false
1077 }
1078
1079 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1081 pub fn score(&self, candidate: usize) -> Option<u64> {
1082 if candidate < self.inner.scores.len() {
1083 Some(self.inner.scores[candidate])
1084 } else {
1085 None
1086 }
1087 }
1088
1089 pub fn winner(&self) -> Option<usize> {
1091 self.inner.allocation
1092 }
1093
1094 pub fn update_score(
1096 &mut self,
1097 candidate: usize,
1098 score: u64,
1099 ) -> (result: Result<(), CompetitiveSelectionError>) {
1100 proof { use_type_invariant(&*self); }
1101 if candidate >= self.inner.scores.len() {
1102 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1103 }
1104 let mut carrier = hard_selection_sentinel();
1105 core::mem::swap(&mut self.inner, &mut carrier);
1106 carrier.update_score(candidate, score);
1107 core::mem::swap(&mut self.inner, &mut carrier);
1108 Ok(())
1109 }
1110
1111 #[expect(clippy::manual_unwrap_or_default, reason = "the explicit match is supported by the Verus boundary")]
1113 pub fn evaluate(&mut self) -> (winner: usize) {
1114 proof { use_type_invariant(&*self); }
1115 let mut carrier = hard_selection_sentinel();
1116 core::mem::swap(&mut self.inner, &mut carrier);
1117 carrier.evaluate();
1118 let winner = match carrier.allocation {
1119 Some(value) => value,
1120 None => 0,
1121 };
1122 core::mem::swap(&mut self.inner, &mut carrier);
1123 winner
1124 }
1125}
1126
1127pub struct CompetitiveSelectionHardExclusive {
1129 inner: CompetitiveSelectionHardExclusiveCarrier,
1130}
1131
1132impl CompetitiveSelectionHardExclusive {
1133 #[verifier::type_invariant]
1134 closed spec fn well_formed(&self) -> bool {
1135 self.inner.inv()
1136 }
1137
1138 pub fn new(
1140 num_seats: usize,
1141 num_candidates: usize,
1142 max_score: u64,
1143 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1144 if num_candidates == 0 {
1145 return Err(CompetitiveSelectionError::NoCandidates);
1146 }
1147 let inner = CompetitiveSelectionHardExclusiveCarrier::new(
1148 num_seats,
1149 num_candidates,
1150 max_score,
1151 );
1152 Ok(Self { inner })
1153 }
1154
1155 pub fn seat_count(&self) -> usize {
1157 self.inner.num_seats
1158 }
1159
1160 pub fn candidate_count(&self) -> usize {
1162 self.inner.num_candidates
1163 }
1164
1165 pub fn max_score(&self) -> u64 {
1167 self.inner.max_score
1168 }
1169
1170 #[expect(clippy::indexing_slicing, reason = "the branch proves the seat index is in bounds")]
1172 #[expect(clippy::manual_map, reason = "the explicit match is supported by the Verus boundary")]
1173 pub fn allocation(&self, seat: usize) -> Option<usize> {
1174 proof { use_type_invariant(&*self); }
1175 if seat >= self.inner.num_seats {
1176 return None;
1177 }
1178 match self.inner.allocation[seat] {
1179 Some(candidate) => Some(candidate as usize),
1180 None => None,
1181 }
1182 }
1183
1184 #[expect(clippy::indexing_slicing, reason = "the branches prove both score indices are in bounds")]
1186 pub fn score(&self, seat: usize, candidate: usize) -> Option<u64> {
1187 proof { use_type_invariant(&*self); }
1188 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1189 None
1190 } else {
1191 Some(self.inner.scores[seat][candidate])
1192 }
1193 }
1194
1195 pub fn candidate_available(&self, seat: usize, candidate: usize) -> Option<bool> {
1197 proof { use_type_invariant(&*self); }
1198 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1199 return None;
1200 }
1201 Some(self.inner.candidate_available(seat, candidate))
1202 }
1203
1204 pub fn update_score(
1206 &mut self,
1207 seat: usize,
1208 candidate: usize,
1209 score: u64,
1210 ) -> (result: Result<(), CompetitiveSelectionError>) {
1211 proof { use_type_invariant(&*self); }
1212 if seat >= self.inner.num_seats {
1213 return Err(CompetitiveSelectionError::SeatOutOfRange);
1214 }
1215 if candidate >= self.inner.num_candidates {
1216 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1217 }
1218 if score > self.inner.max_score {
1219 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1220 }
1221 let mut carrier = hard_exclusive_selection_sentinel();
1222 core::mem::swap(&mut self.inner, &mut carrier);
1223 carrier.update_score(seat, candidate, score);
1224 core::mem::swap(&mut self.inner, &mut carrier);
1225 Ok(())
1226 }
1227
1228 #[expect(clippy::indexing_slicing, reason = "the guards prove the seat index is in bounds")]
1230 pub fn evaluate(
1231 &mut self,
1232 seat: usize,
1233 ) -> (result: Result<usize, CompetitiveSelectionError>) {
1234 proof { use_type_invariant(&*self); }
1235 if seat >= self.inner.num_seats {
1236 return Err(CompetitiveSelectionError::SeatOutOfRange);
1237 }
1238 if self.inner.allocation[seat].is_some() {
1239 return Err(CompetitiveSelectionError::SeatAlreadyAllocated);
1240 }
1241 if !self.inner.has_available(seat) {
1242 return Err(CompetitiveSelectionError::NoCandidateAvailable);
1243 }
1244 let mut carrier = hard_exclusive_selection_sentinel();
1245 core::mem::swap(&mut self.inner, &mut carrier);
1246 carrier.evaluate(seat);
1247 let winner = match carrier.allocation[seat] {
1248 Some(candidate) => candidate as usize,
1249 None => 0,
1250 };
1251 core::mem::swap(&mut self.inner, &mut carrier);
1252 Ok(winner)
1253 }
1254}
1255
1256pub struct CompetitiveSelectionSoft {
1258 inner: CompetitiveSelectionSoftCarrier,
1259}
1260
1261impl CompetitiveSelectionSoft {
1262 #[verifier::type_invariant]
1263 closed spec fn well_formed(&self) -> bool {
1264 self.inner.mutable_score_inv()
1265 }
1266
1267 pub fn new(
1269 scores: Vec<u64>,
1270 weight_total: u64,
1271 max_score: u64,
1272 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1273 if scores.is_empty() {
1274 return Err(CompetitiveSelectionError::NoCandidates);
1275 }
1276 if weight_total > 1_000_000_000 {
1277 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1278 }
1279 if max_score > 1_000_000_000 {
1280 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1281 }
1282 if weight_total < scores.len() as u64 {
1283 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1284 }
1285 if !positive_values_within_max(&scores, max_score) {
1286 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1287 }
1288 let inner = CompetitiveSelectionSoftCarrier::new(scores, weight_total, max_score);
1289 Ok(Self { inner })
1290 }
1291
1292 pub fn begin(
1294 scores: Vec<u64>,
1295 weight_total: u64,
1296 max_score: u64,
1297 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1298 if scores.is_empty() {
1299 return Err(CompetitiveSelectionError::NoCandidates);
1300 }
1301 if weight_total > 1_000_000_000 {
1302 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1303 }
1304 if max_score > 1_000_000_000 {
1305 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1306 }
1307 if weight_total < scores.len() as u64 {
1308 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1309 }
1310 if !positive_values_within_max(&scores, max_score) {
1311 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1312 }
1313 let inner = CompetitiveSelectionSoftCarrier::init(scores, weight_total, max_score);
1314 Ok(Self { inner })
1315 }
1316
1317 pub fn len(&self) -> usize {
1319 self.inner.scores.len()
1320 }
1321
1322 pub fn is_empty(&self) -> bool {
1324 false
1325 }
1326
1327 pub fn weight_total(&self) -> u64 {
1329 self.inner.weight_total
1330 }
1331
1332 pub fn max_score(&self) -> u64 {
1334 self.inner.max_score
1335 }
1336
1337 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1339 pub fn score(&self, candidate: usize) -> Option<u64> {
1340 if candidate < self.inner.scores.len() {
1341 Some(self.inner.scores[candidate])
1342 } else {
1343 None
1344 }
1345 }
1346
1347 pub fn weight(&self, candidate: usize) -> Option<u64> {
1349 proof { use_type_invariant(&*self); }
1350 if candidate < self.inner.extra.len() {
1351 Some(self.inner.weight_at(candidate))
1352 } else {
1353 None
1354 }
1355 }
1356
1357 pub fn assigned_weight(&self) -> u64 {
1359 proof { use_type_invariant(&*self); }
1360 self.inner.assigned_weight()
1361 }
1362
1363 pub fn is_complete(&self) -> bool {
1365 self.assigned_weight() == self.inner.weight_total
1366 }
1367
1368 pub fn assign_next(&mut self) -> (result: Result<usize, CompetitiveSelectionError>) {
1370 proof { use_type_invariant(&*self); }
1371 if self.inner.assigned_weight() >= self.inner.weight_total {
1372 return Err(CompetitiveSelectionError::AllocationComplete);
1373 }
1374 let mut carrier = soft_selection_sentinel();
1375 core::mem::swap(&mut self.inner, &mut carrier);
1376 let winner = carrier.assign_next();
1377 core::mem::swap(&mut self.inner, &mut carrier);
1378 Ok(winner)
1379 }
1380
1381 pub fn update_score(
1383 &mut self,
1384 candidate: usize,
1385 score: u64,
1386 ) -> (result: Result<(), CompetitiveSelectionError>) {
1387 proof { use_type_invariant(&*self); }
1388 if candidate >= self.inner.scores.len() {
1389 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1390 }
1391 if score < 1 || score > self.inner.max_score {
1392 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1393 }
1394 let mut carrier = soft_selection_sentinel();
1395 core::mem::swap(&mut self.inner, &mut carrier);
1396 carrier.update_score(candidate, score);
1397 core::mem::swap(&mut self.inner, &mut carrier);
1398 Ok(())
1399 }
1400}
1401
1402pub struct CompetitiveSelectionRanked {
1404 inner: CompetitiveSelectionRankedCarrier,
1405}
1406
1407impl CompetitiveSelectionRanked {
1408 #[verifier::type_invariant]
1409 closed spec fn well_formed(&self) -> bool {
1410 self.inner.inv()
1411 }
1412
1413 pub fn new(
1415 scores: Vec<u64>,
1416 k: usize,
1417 max_score: u64,
1418 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1419 if !values_within_max(&scores, max_score) {
1420 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1421 }
1422 let inner = CompetitiveSelectionRankedCarrier::new(scores, k, max_score);
1423 Ok(Self { inner })
1424 }
1425
1426 pub fn len(&self) -> usize {
1428 self.inner.scores.len()
1429 }
1430
1431 pub fn is_empty(&self) -> bool {
1433 self.inner.scores.is_empty()
1434 }
1435
1436 pub fn limit(&self) -> usize {
1438 self.inner.k
1439 }
1440
1441 pub fn max_score(&self) -> u64 {
1443 self.inner.max_score
1444 }
1445
1446 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1448 pub fn score(&self, candidate: usize) -> Option<u64> {
1449 if candidate < self.inner.scores.len() {
1450 Some(self.inner.scores[candidate])
1451 } else {
1452 None
1453 }
1454 }
1455
1456 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1458 pub fn is_selected(&self, candidate: usize) -> Option<bool> {
1459 if candidate < self.inner.selected.len() {
1460 Some(self.inner.selected[candidate])
1461 } else {
1462 None
1463 }
1464 }
1465
1466 pub fn select(&mut self) {
1468 proof { use_type_invariant(&*self); }
1469 let mut carrier = ranked_selection_sentinel();
1470 core::mem::swap(&mut self.inner, &mut carrier);
1471 carrier.select();
1472 core::mem::swap(&mut self.inner, &mut carrier);
1473 }
1474
1475 pub fn update_scores(
1477 &mut self,
1478 scores: Vec<u64>,
1479 ) -> (result: Result<(), CompetitiveSelectionError>) {
1480 proof { use_type_invariant(&*self); }
1481 if scores.len() != self.inner.scores.len() {
1482 return Err(CompetitiveSelectionError::ScoreCountMismatch);
1483 }
1484 if !values_within_max(&scores, self.inner.max_score) {
1485 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1486 }
1487 let mut carrier = ranked_selection_sentinel();
1488 core::mem::swap(&mut self.inner, &mut carrier);
1489 carrier.update_scores(scores);
1490 core::mem::swap(&mut self.inner, &mut carrier);
1491 Ok(())
1492 }
1493}
1494
1495#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1497#[non_exhaustive]
1498pub enum ConvergenceBuildError {
1499 ThresholdOutOfRange,
1501 EmptyWindow,
1503 WindowSumOutOfRange,
1505}
1506
1507#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1509#[non_exhaustive]
1510pub enum ConvergenceError {
1511 DeltaOutOfRange,
1513}
1514
1515pub struct ConvergenceGovernor {
1517 inner: ConvergenceGovernorCarrier,
1518}
1519
1520impl ConvergenceGovernor {
1521 #[verifier::type_invariant]
1522 closed spec fn well_formed(&self) -> bool {
1523 self.inner.inv()
1524 }
1525
1526 pub fn new(
1528 threshold: u64,
1529 awaken_threshold: u64,
1530 window: usize,
1531 max_delta: u64,
1532 ) -> (result: Result<Self, ConvergenceBuildError>) {
1533 if threshold > u64::MAX / 2 {
1534 return Err(ConvergenceBuildError::ThresholdOutOfRange);
1535 }
1536 if window == 0 {
1537 return Err(ConvergenceBuildError::EmptyWindow);
1538 }
1539 if window > 1_000_000_000 || max_delta > 1_000_000_000 {
1540 return Err(ConvergenceBuildError::WindowSumOutOfRange);
1541 }
1542 proof {
1543 assert(window as int * max_delta as int <= u64::MAX as int) by (nonlinear_arith)
1544 requires
1545 window <= 1_000_000_000,
1546 max_delta <= 1_000_000_000,
1547 u64::MAX >= 1_000_000_000 * 1_000_000_000;
1548 }
1549 let inner = ConvergenceGovernorCarrier::new(
1550 threshold,
1551 awaken_threshold,
1552 window,
1553 max_delta,
1554 );
1555 Ok(Self { inner })
1556 }
1557
1558 pub fn threshold(&self) -> u64 {
1560 self.inner.threshold
1561 }
1562
1563 pub fn awaken_threshold(&self) -> u64 {
1565 self.inner.awaken_threshold
1566 }
1567
1568 pub fn window(&self) -> usize {
1570 self.inner.window
1571 }
1572
1573 pub fn max_delta(&self) -> u64 {
1575 self.inner.max_delta
1576 }
1577
1578 pub fn state(&self) -> ConvergenceState {
1580 self.inner.state
1581 }
1582
1583 pub fn phase(&self) -> ConvergencePhase {
1585 self.inner.gradient_phase
1586 }
1587
1588 pub fn peak_observed(&self) -> bool {
1590 self.inner.peak_observed
1591 }
1592
1593 pub fn history_len(&self) -> usize {
1595 self.inner.delta_history.len()
1596 }
1597
1598 #[expect(clippy::indexing_slicing, reason = "the branch proves the history index is in bounds")]
1600 pub fn history(&self, index: usize) -> Option<u64> {
1601 if index < self.inner.delta_history.len() {
1602 Some(self.inner.delta_history[index])
1603 } else {
1604 None
1605 }
1606 }
1607
1608 pub fn update(&mut self, delta: u64) -> (result: Result<u64, ConvergenceError>) {
1610 proof { use_type_invariant(&*self); }
1611 if delta > self.inner.max_delta {
1612 return Err(ConvergenceError::DeltaOutOfRange);
1613 }
1614 let mut carrier = convergence_sentinel();
1615 core::mem::swap(&mut self.inner, &mut carrier);
1616 let average = carrier.update(delta);
1617 core::mem::swap(&mut self.inner, &mut carrier);
1618 Ok(average)
1619 }
1620}
1621
1622fn budget_sentinel() -> (carrier: BudgetCarrier)
1623 ensures carrier.safety_invariant(),
1624{
1625 BudgetCarrier::new(0)
1626}
1627
1628fn registry_sentinel() -> (carrier: RegistryCarrier)
1629 ensures carrier.unique_mapping(),
1630{
1631 RegistryCarrier::new()
1632}
1633
1634fn audit_sentinel() -> (carrier: AuditSinkCarrier)
1635 ensures carrier.inv(),
1636{
1637 AuditSinkCarrier::new(0)
1638}
1639
1640fn propagation_sentinel() -> (carrier: PropagationPassCarrier)
1641 ensures carrier.inv(),
1642{
1643 let edges: Vec<(usize, usize)> = Vec::new();
1644 let values: Vec<u64> = Vec::new();
1645 PropagationPassCarrier::new(0, 0, 0, edges, values)
1646}
1647
1648fn actuation_sentinel() -> (carrier: ActuationPassCarrier)
1649 ensures carrier.invariant(),
1650{
1651 let allocation: Vec<Option<u64>> = Vec::new();
1652 ActuationPassCarrier::new(allocation, 0)
1653}
1654
1655fn quality_hierarchy_sentinel() -> (carrier: QualityHierarchyCarrier)
1656 ensures
1657 carrier.type_invariant(),
1658 carrier.strict_level_descent(),
1659 carrier.parent_edge_agreement(),
1660 carrier.cost_monotonicity(),
1661{
1662 QualityHierarchyCarrier::new(0, 0)
1663}
1664
1665fn backtracking_sentinel() -> (carrier: BacktrackingTraversalCarrier)
1666 ensures carrier.inv(),
1667{
1668 BacktrackingTraversalCarrier::new(0, 0, 0)
1669}
1670
1671fn hard_selection_sentinel() -> (carrier: CompetitiveSelectionHardCarrier)
1672 ensures
1673 carrier.inv(),
1674 carrier.scores.len() >= 1,
1675{
1676 CompetitiveSelectionHardCarrier::new(1)
1677}
1678
1679fn hard_exclusive_selection_sentinel() -> (carrier: CompetitiveSelectionHardExclusiveCarrier)
1680 ensures carrier.inv(),
1681{
1682 CompetitiveSelectionHardExclusiveCarrier::new(0, 1, 0)
1683}
1684
1685fn soft_selection_sentinel() -> (carrier: CompetitiveSelectionSoftCarrier)
1686 ensures carrier.mutable_score_inv(),
1687{
1688 let mut scores: Vec<u64> = Vec::new();
1689 scores.push(1);
1690 CompetitiveSelectionSoftCarrier::init(scores, 1, 1)
1691}
1692
1693fn ranked_selection_sentinel() -> (carrier: CompetitiveSelectionRankedCarrier)
1694 ensures carrier.inv(),
1695{
1696 let scores: Vec<u64> = Vec::new();
1697 CompetitiveSelectionRankedCarrier::new(scores, 0, 0)
1698}
1699
1700fn convergence_sentinel() -> (carrier: ConvergenceGovernorCarrier)
1701 ensures carrier.inv(),
1702{
1703 ConvergenceGovernorCarrier::new(0, 0, 1, 0)
1704}
1705
1706#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
1707#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
1708#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
1709pub(crate) fn values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
1710 ensures
1711 valid == (forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value),
1712{
1713 let mut index: usize = 0;
1714 while index < values.len()
1715 invariant
1716 index <= values.len(),
1717 forall|i: int| 0 <= i < index ==> values@[i] <= max_value,
1718 decreases values.len() - index,
1719 {
1720 if values[index] > max_value {
1721 assert(!(forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value));
1722 return false;
1723 }
1724 index += 1;
1725 }
1726 true
1727}
1728
1729#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
1730#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
1731#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
1732fn positive_values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
1733 ensures
1734 valid == (forall|i: int| 0 <= i < values.len()
1735 ==> 1 <= #[trigger] values@[i] <= max_value),
1736{
1737 let mut index: usize = 0;
1738 while index < values.len()
1739 invariant
1740 index <= values.len(),
1741 forall|i: int| 0 <= i < index ==> 1 <= #[trigger] values@[i] <= max_value,
1742 decreases values.len() - index,
1743 {
1744 if values[index] < 1 || values[index] > max_value {
1745 assert(!(forall|i: int| 0 <= i < values.len()
1746 ==> 1 <= #[trigger] values@[i] <= max_value));
1747 return false;
1748 }
1749 index += 1;
1750 }
1751 true
1752}
1753
1754#[expect(clippy::indexing_slicing, reason = "the loop proves the edge index is in bounds")]
1755#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
1756#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
1757fn edges_within_nodes(edges: &Vec<(usize, usize)>, num_nodes: usize) -> (valid: bool)
1758 ensures
1759 valid == (forall|i: int| 0 <= i < edges.len()
1760 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes),
1761{
1762 let mut index: usize = 0;
1763 while index < edges.len()
1764 invariant
1765 index <= edges.len(),
1766 forall|i: int| 0 <= i < index
1767 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes,
1768 decreases edges.len() - index,
1769 {
1770 if edges[index].0 >= num_nodes || edges[index].1 >= num_nodes {
1771 assert(!(forall|i: int| 0 <= i < edges.len()
1772 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes));
1773 return false;
1774 }
1775 index += 1;
1776 }
1777 true
1778}
1779
1780} impl Default for ResourceRegistry {
1783 fn default() -> Self {
1784 Self::new()
1785 }
1786}
1787
1788macro_rules! impl_observational_debug {
1789 ($type:ty, $name:literal, $($field:literal => $method:ident),+ $(,)?) => {
1790 impl core::fmt::Debug for $type {
1791 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1792 let mut state = formatter.debug_struct($name);
1793 $(state.field($field, &self.$method());)+
1794 state.finish()
1795 }
1796 }
1797 };
1798}
1799
1800impl_observational_debug!(Budget, "Budget",
1801 "capacity" => capacity,
1802 "allocated" => allocated,
1803 "reserved" => reserved,
1804 "pending_eviction" => pending_eviction,
1805 "available" => available,
1806);
1807impl_observational_debug!(ResourceRegistry, "ResourceRegistry", "len" => len);
1808impl_observational_debug!(AuditSink, "AuditSink",
1809 "capacity" => capacity,
1810 "len" => len,
1811 "last_hash" => last_hash,
1812 "valid" => validate,
1813);
1814impl_observational_debug!(Cursor, "Cursor", "position" => position);
1815impl_observational_debug!(PropagationPass, "PropagationPass",
1816 "num_nodes" => num_nodes,
1817 "max_iterations" => max_iterations,
1818 "iteration" => iteration,
1819 "round" => round,
1820 "changed" => changed,
1821);
1822impl_observational_debug!(ActuationPass, "ActuationPass",
1823 "len" => len,
1824 "complete" => is_complete,
1825 "ready_to_finish" => ready_to_finish,
1826);
1827impl_observational_debug!(QualityHierarchy, "QualityHierarchy",
1828 "len" => len,
1829 "max_level" => max_level,
1830 "edge_count" => edge_count,
1831);
1832impl_observational_debug!(BacktrackingTraversal, "BacktrackingTraversal",
1833 "max_depth" => max_depth,
1834 "depth" => depth,
1835 "auxiliary" => auxiliary,
1836 "visited_count" => visited_count,
1837 "leaf" => is_leaf,
1838);
1839impl_observational_debug!(CompetitiveSelectionHard, "CompetitiveSelectionHard",
1840 "len" => len,
1841 "winner" => winner,
1842);
1843impl_observational_debug!(CompetitiveSelectionHardExclusive, "CompetitiveSelectionHardExclusive",
1844 "seat_count" => seat_count,
1845 "candidate_count" => candidate_count,
1846 "max_score" => max_score,
1847);
1848impl_observational_debug!(CompetitiveSelectionSoft, "CompetitiveSelectionSoft",
1849 "len" => len,
1850 "weight_total" => weight_total,
1851 "assigned_weight" => assigned_weight,
1852 "max_score" => max_score,
1853 "complete" => is_complete,
1854);
1855impl_observational_debug!(CompetitiveSelectionRanked, "CompetitiveSelectionRanked",
1856 "len" => len,
1857 "limit" => limit,
1858 "max_score" => max_score,
1859);
1860impl_observational_debug!(ConvergenceGovernor, "ConvergenceGovernor",
1861 "threshold" => threshold,
1862 "awaken_threshold" => awaken_threshold,
1863 "window" => window,
1864 "max_delta" => max_delta,
1865 "state" => state,
1866 "phase" => phase,
1867 "peak_observed" => peak_observed,
1868 "history_len" => history_len,
1869);
1870
1871impl core::fmt::Display for BudgetError {
1872 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1873 formatter.write_str(match self {
1874 Self::AmountExceedsReservation => "amount exceeds the held reservation",
1875 Self::AmountExceedsAllocation => "amount exceeds the committed allocation",
1876 Self::AmountExceedsPendingEviction => "amount exceeds pending eviction",
1877 })
1878 }
1879}
1880
1881impl std::error::Error for BudgetError {}
1882
1883impl core::fmt::Display for CursorError {
1884 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1885 formatter.write_str(match self {
1886 Self::Regression => "cursor movement would regress the retained position",
1887 })
1888 }
1889}
1890
1891impl std::error::Error for CursorError {}
1892
1893impl core::fmt::Display for PropagationBuildError {
1894 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1895 formatter.write_str(match self {
1896 Self::InitialValueOutOfRange => "an initial value exceeds the declared value ceiling",
1897 Self::EdgeEndpointOutOfRange => "an edge endpoint is outside the admitted node set",
1898 })
1899 }
1900}
1901
1902impl std::error::Error for PropagationBuildError {}
1903
1904impl core::fmt::Display for PropagationError {
1905 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1906 formatter.write_str(match self {
1907 Self::NodeOutOfRange => "node is outside the admitted graph",
1908 Self::RoundAlreadyRunning => "a propagation round is already running",
1909 Self::RoundNotRunning => "no propagation round is running",
1910 Self::NodeAlreadyUpdated => "node already committed an update in this round",
1911 Self::RoundIncomplete => "not every node committed an update",
1912 Self::PassTerminated => "propagation pass is settled or exhausted",
1913 Self::PassStillRunning => "propagation pass has not reached a terminal state",
1914 })
1915 }
1916}
1917
1918impl std::error::Error for PropagationError {}
1919
1920impl core::fmt::Display for ActuationError {
1921 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1922 formatter.write_str(match self {
1923 Self::SeatOutOfRange => "seat is outside the admitted seat set",
1924 Self::PassComplete => "actuation pass is already complete",
1925 Self::SeatAlreadyAllocated => "seat already holds a resource",
1926 Self::SeatUnallocated => "seat holds no resource",
1927 Self::SeatAlreadyActuated => "seat already committed its effect",
1928 Self::PassIncomplete => "an allocated seat has not committed its effect",
1929 })
1930 }
1931}
1932
1933impl std::error::Error for ActuationError {}
1934
1935impl core::fmt::Display for QualityHierarchyError {
1936 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1937 formatter.write_str(match self {
1938 Self::NodeOutOfRange => "node is outside the admitted hierarchy",
1939 Self::ParentOutOfRange => "parent is outside the admitted hierarchy",
1940 Self::ChildOutOfRange => "child is outside the admitted hierarchy",
1941 Self::LevelOutOfRange => "level exceeds the hierarchy ceiling",
1942 Self::CostOutOfRange => "cost exceeds the hierarchy ceiling",
1943 Self::NodeNotIsolated => "node properties may change only while the node is isolated",
1944 Self::SelfEdge => "a hierarchy node cannot be its own child",
1945 Self::EdgeAlreadyExists => "the parent-child edge already exists",
1946 Self::ChildAlreadyParented => "the child already has a parent",
1947 Self::LevelOrderViolation => "parent level must strictly exceed child level",
1948 Self::CostOrderViolation => "parent cost must not exceed child cost",
1949 })
1950 }
1951}
1952
1953impl std::error::Error for QualityHierarchyError {}
1954
1955impl core::fmt::Display for BacktrackingBuildError {
1956 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1957 formatter.write_str(match self {
1958 Self::InitialAuxOutOfRange => {
1959 "initial auxiliary value is outside the modulo-three domain"
1960 }
1961 })
1962 }
1963}
1964
1965impl std::error::Error for BacktrackingBuildError {}
1966
1967impl core::fmt::Display for BacktrackingError {
1968 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1969 formatter.write_str(match self {
1970 Self::AtLeaf => "descent is disabled at a leaf",
1971 Self::ChoiceOutOfRange => "branch choice is outside the admitted branch set",
1972 Self::DeltaOutOfRange => "mutation delta must be one or two",
1973 Self::NotLeaf => "visit requires a full-depth leaf",
1974 Self::AlreadyVisited => "the current leaf was already visited",
1975 Self::AtRoot => "ascent is disabled at the root",
1976 })
1977 }
1978}
1979
1980impl std::error::Error for BacktrackingError {}
1981
1982impl core::fmt::Display for CompetitiveSelectionError {
1983 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1984 formatter.write_str(match self {
1985 Self::NoCandidates => "at least one candidate is required",
1986 Self::CandidateOutOfRange => "candidate is outside the admitted candidate set",
1987 Self::SeatOutOfRange => "seat is outside the admitted seat set",
1988 Self::SeatAlreadyAllocated => "seat already holds an allocation",
1989 Self::NoCandidateAvailable => "no candidate is available for the seat",
1990 Self::ScoreOutOfRange => "score is outside the admitted score domain",
1991 Self::ScoreCountMismatch => "replacement scores have a different candidate count",
1992 Self::WeightTotalBelowReservedFloor => {
1993 "weight total is smaller than the reserved candidate floor"
1994 }
1995 Self::WeightTotalOutOfRange => "weight total exceeds the verified arithmetic ceiling",
1996 Self::MaxScoreOutOfRange => "maximum score exceeds the verified arithmetic ceiling",
1997 Self::AllocationComplete => "all soft-selection weight has been assigned",
1998 })
1999 }
2000}
2001
2002impl std::error::Error for CompetitiveSelectionError {}
2003
2004impl core::fmt::Display for ConvergenceBuildError {
2005 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2006 formatter.write_str(match self {
2007 Self::ThresholdOutOfRange => "convergence threshold cannot be doubled safely",
2008 Self::EmptyWindow => "convergence history window must be nonempty",
2009 Self::WindowSumOutOfRange => "maximum convergence window sum exceeds u64",
2010 })
2011 }
2012}
2013
2014impl std::error::Error for ConvergenceBuildError {}
2015
2016impl core::fmt::Display for ConvergenceError {
2017 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2018 formatter.write_str(match self {
2019 Self::DeltaOutOfRange => "delta exceeds the configured maximum",
2020 })
2021 }
2022}
2023
2024impl std::error::Error for ConvergenceError {}