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 {
55 inner: BudgetCarrier,
56}
57
58impl Budget {
59 #[verifier::type_invariant]
60 closed spec fn well_formed(&self) -> bool {
61 self.inner.safety_invariant()
62 }
63
64 pub fn new(capacity: u64) -> (budget: Self) {
66 let inner = BudgetCarrier::new(capacity);
67 Self { inner }
68 }
69
70 pub fn capacity(&self) -> u64 {
72 self.inner.capacity
73 }
74
75 pub fn allocated(&self) -> u64 {
77 self.inner.allocated
78 }
79
80 pub fn reserved(&self) -> u64 {
82 self.inner.reserved
83 }
84
85 pub fn pending_eviction(&self) -> u64 {
87 self.inner.pending_eviction
88 }
89
90 pub fn available(&self) -> (available: u64) {
92 proof { use_type_invariant(&*self); }
93 self.inner.available()
94 }
95
96 #[must_use]
98 pub fn try_allocate(&mut self, amount: u64) -> (accepted: bool) {
99 proof { use_type_invariant(&*self); }
100 let mut carrier = budget_sentinel();
101 core::mem::swap(&mut self.inner, &mut carrier);
102 let accepted = carrier.try_allocate(amount);
103 core::mem::swap(&mut self.inner, &mut carrier);
104 accepted
105 }
106
107 #[must_use]
109 pub fn try_reserve(&mut self, amount: u64) -> (accepted: bool) {
110 proof { use_type_invariant(&*self); }
111 let mut carrier = budget_sentinel();
112 core::mem::swap(&mut self.inner, &mut carrier);
113 let accepted = carrier.reserve(amount);
114 core::mem::swap(&mut self.inner, &mut carrier);
115 accepted
116 }
117
118 pub fn commit_reservation(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
124 proof { use_type_invariant(&*self); }
125 if amount <= self.inner.reserved {
126 let mut carrier = budget_sentinel();
127 core::mem::swap(&mut self.inner, &mut carrier);
128 carrier.commit_reservation(amount);
129 core::mem::swap(&mut self.inner, &mut carrier);
130 Ok(())
131 } else {
132 Err(BudgetError::AmountExceedsReservation)
133 }
134 }
135
136 pub fn release(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
142 proof { use_type_invariant(&*self); }
143 if amount <= self.inner.allocated {
144 let mut carrier = budget_sentinel();
145 core::mem::swap(&mut self.inner, &mut carrier);
146 carrier.release(amount);
147 core::mem::swap(&mut self.inner, &mut carrier);
148 Ok(())
149 } else {
150 Err(BudgetError::AmountExceedsAllocation)
151 }
152 }
153
154 pub fn mark_eviction(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
160 proof { use_type_invariant(&*self); }
161 if amount <= self.inner.allocated {
162 let mut carrier = budget_sentinel();
163 core::mem::swap(&mut self.inner, &mut carrier);
164 carrier.mark_eviction(amount);
165 core::mem::swap(&mut self.inner, &mut carrier);
166 Ok(())
167 } else {
168 Err(BudgetError::AmountExceedsAllocation)
169 }
170 }
171
172 pub fn complete_eviction(&mut self, amount: u64) -> (result: Result<(), BudgetError>) {
178 proof { use_type_invariant(&*self); }
179 if amount <= self.inner.pending_eviction {
180 let mut carrier = budget_sentinel();
181 core::mem::swap(&mut self.inner, &mut carrier);
182 carrier.complete_eviction(amount);
183 core::mem::swap(&mut self.inner, &mut carrier);
184 Ok(())
185 } else {
186 Err(BudgetError::AmountExceedsPendingEviction)
187 }
188 }
189}
190
191pub struct ResourceRegistry {
203 inner: RegistryCarrier<u64, u64>,
204}
205
206impl ResourceRegistry {
207 #[verifier::type_invariant]
208 closed spec fn well_formed(&self) -> bool {
209 self.inner.unique_mapping()
210 }
211
212 pub fn new() -> (registry: Self) {
214 let inner = RegistryCarrier::new();
215 Self { inner }
216 }
217
218 pub fn len(&self) -> usize {
220 self.inner.entries.len()
221 }
222
223 pub fn is_empty(&self) -> bool {
225 self.inner.entries.is_empty()
226 }
227
228 pub fn get(&self, key: u64) -> (value: Option<u64>) {
230 proof { use_type_invariant(&*self); }
231 self.inner.lookup(key)
232 }
233
234 pub fn insert(&mut self, key: u64, value: u64) -> (previous: Option<u64>) {
236 proof { use_type_invariant(&*self); }
237 let previous = self.inner.lookup(key);
238 let mut carrier = registry_sentinel();
239 core::mem::swap(&mut self.inner, &mut carrier);
240 carrier.register(key, value);
241 core::mem::swap(&mut self.inner, &mut carrier);
242 previous
243 }
244
245 pub fn remove(&mut self, key: u64) -> (previous: Option<u64>) {
247 proof { use_type_invariant(&*self); }
248 let previous = self.inner.lookup(key);
249 match previous {
250 Some(value) => {
251 let mut carrier = registry_sentinel();
252 core::mem::swap(&mut self.inner, &mut carrier);
253 carrier.deregister(key);
254 core::mem::swap(&mut self.inner, &mut carrier);
255 Some(value)
256 },
257 None => None,
258 }
259 }
260
261 #[expect(clippy::indexing_slicing, reason = "the branch proves the registry index is in bounds")]
263 pub fn entry(&self, index: usize) -> Option<(u64, u64)> {
264 if index < self.inner.entries.len() {
265 Some(self.inner.entries[index])
266 } else {
267 None
268 }
269 }
270}
271
272#[derive(Clone, Copy, Debug, Eq, PartialEq)]
288pub struct AuditRecord {
289 pub operation: u64,
291 pub previous_hash: u64,
293 pub hash: u64,
295}
296
297pub struct AuditSink {
314 inner: AuditSinkCarrier,
315}
316
317impl AuditSink {
318 #[verifier::type_invariant]
319 closed spec fn well_formed(&self) -> bool {
320 self.inner.inv()
321 }
322
323 pub fn new(capacity: usize) -> (sink: Self) {
325 let inner = AuditSinkCarrier::new(capacity);
326 Self { inner }
327 }
328
329 pub fn capacity(&self) -> usize {
331 self.inner.max_log_len
332 }
333
334 pub fn len(&self) -> usize {
336 self.inner.log.len()
337 }
338
339 pub fn is_empty(&self) -> bool {
341 self.inner.log.is_empty()
342 }
343
344 pub fn last_hash(&self) -> u64 {
346 self.inner.last_hash
347 }
348
349 #[must_use]
351 pub fn try_record(&mut self, operation: u64) -> (accepted: bool) {
352 proof { use_type_invariant(&*self); }
353 let mut carrier = audit_sentinel();
354 core::mem::swap(&mut self.inner, &mut carrier);
355 let accepted = carrier.record(operation);
356 core::mem::swap(&mut self.inner, &mut carrier);
357 accepted
358 }
359
360 pub fn validate(&self) -> (valid: bool) {
365 proof { use_type_invariant(&*self); }
366 self.inner.validate()
367 }
368
369 #[expect(clippy::indexing_slicing, reason = "the branch proves the audit index is in bounds")]
371 pub fn record(&self, index: usize) -> Option<AuditRecord> {
372 if index < self.inner.log.len() {
373 let entry = &self.inner.log[index];
374 Some(AuditRecord {
375 operation: entry.operation,
376 previous_hash: entry.prev_hash,
377 hash: entry.hash,
378 })
379 } else {
380 None
381 }
382 }
383}
384
385#[derive(Clone, Copy, Debug, Eq, PartialEq)]
387#[non_exhaustive]
388pub enum CursorError {
389 Regression,
391}
392
393pub struct Cursor {
406 inner: CursorCarrier,
407}
408
409impl Cursor {
410 pub fn new(position: usize) -> (cursor: Self) {
412 Self { inner: CursorCarrier::new(position) }
413 }
414
415 pub fn position(&self) -> usize {
417 self.inner.position
418 }
419
420 pub fn advance_to(&mut self, position: usize) -> (result: Result<(), CursorError>) {
426 if position < self.inner.position {
427 return Err(CursorError::Regression);
428 }
429 self.inner.advance_to(position);
430 Ok(())
431 }
432}
433
434#[derive(Clone, Copy, Debug, Eq, PartialEq)]
436#[non_exhaustive]
437pub enum PropagationBuildError {
438 InitialValueOutOfRange,
440 EdgeEndpointOutOfRange,
442}
443
444#[derive(Clone, Copy, Debug, Eq, PartialEq)]
446#[non_exhaustive]
447pub enum PropagationError {
448 NodeOutOfRange,
450 RoundAlreadyRunning,
452 RoundNotRunning,
454 NodeAlreadyUpdated,
456 RoundIncomplete,
458 PassTerminated,
460 PassStillRunning,
462}
463
464pub struct PropagationPass {
480 inner: PropagationPassCarrier,
481}
482
483impl PropagationPass {
484 #[verifier::type_invariant]
485 closed spec fn well_formed(&self) -> bool {
486 self.inner.inv()
487 }
488
489 pub fn new(
495 max_iterations: u64,
496 max_value: u64,
497 edges: Vec<(usize, usize)>,
498 initial_values: Vec<u64>,
499 ) -> (result: Result<Self, PropagationBuildError>) {
500 if !values_within_max(&initial_values, max_value) {
501 return Err(PropagationBuildError::InitialValueOutOfRange);
502 }
503 let num_nodes = initial_values.len();
504 if !edges_within_nodes(&edges, num_nodes) {
505 return Err(PropagationBuildError::EdgeEndpointOutOfRange);
506 }
507 let inner = PropagationPassCarrier::new(
508 num_nodes,
509 max_iterations,
510 max_value,
511 edges,
512 initial_values,
513 );
514 Ok(Self { inner })
515 }
516
517 pub fn num_nodes(&self) -> usize {
519 self.inner.num_nodes
520 }
521
522 pub fn max_iterations(&self) -> u64 {
524 self.inner.max_iterations
525 }
526
527 pub fn max_value(&self) -> u64 {
529 self.inner.max_value
530 }
531
532 pub fn iteration(&self) -> u64 {
534 self.inner.iteration
535 }
536
537 pub fn round(&self) -> PropagationRound {
539 self.inner.round
540 }
541
542 pub fn changed(&self) -> bool {
544 self.inner.changed
545 }
546
547 #[expect(clippy::indexing_slicing, reason = "the branch proves the node index is in bounds")]
549 pub fn value(&self, node: usize) -> Option<u64> {
550 if node < self.inner.values.len() {
551 Some(self.inner.values[node])
552 } else {
553 None
554 }
555 }
556
557 #[expect(clippy::indexing_slicing, reason = "the branch proves the snapshot index is in bounds")]
559 pub fn snapshot_value(&self, node: usize) -> Option<u64> {
560 if node < self.inner.snapshot.len() {
561 Some(self.inner.snapshot[node])
562 } else {
563 None
564 }
565 }
566
567 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
569 pub fn node_updated(&self, node: usize) -> Option<bool> {
570 if node < self.inner.updated.len() {
571 Some(self.inner.updated[node])
572 } else {
573 None
574 }
575 }
576
577 pub fn start_round(&mut self) -> (result: Result<(), PropagationError>) {
583 proof { use_type_invariant(&*self); }
584 match self.inner.round {
585 PropagationRound::Running => {
586 return Err(PropagationError::RoundAlreadyRunning);
587 },
588 PropagationRound::Idle => {},
589 }
590 if !self.inner.changed || self.inner.iteration >= self.inner.max_iterations {
591 return Err(PropagationError::PassTerminated);
592 }
593 let mut carrier = propagation_sentinel();
594 core::mem::swap(&mut self.inner, &mut carrier);
595 carrier.start_round();
596 core::mem::swap(&mut self.inner, &mut carrier);
597 Ok(())
598 }
599
600 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
606 pub fn update_node(&mut self, node: usize) -> (result: Result<(), PropagationError>) {
607 proof { use_type_invariant(&*self); }
608 match self.inner.round {
609 PropagationRound::Idle => {
610 return Err(PropagationError::RoundNotRunning);
611 },
612 PropagationRound::Running => {},
613 }
614 if node >= self.inner.num_nodes {
615 return Err(PropagationError::NodeOutOfRange);
616 }
617 if self.inner.updated[node] {
618 return Err(PropagationError::NodeAlreadyUpdated);
619 }
620 let mut carrier = propagation_sentinel();
621 core::mem::swap(&mut self.inner, &mut carrier);
622 carrier.update_node(node);
623 core::mem::swap(&mut self.inner, &mut carrier);
624 Ok(())
625 }
626
627 pub fn end_round(&mut self) -> (result: Result<(), PropagationError>) {
633 proof { use_type_invariant(&*self); }
634 match self.inner.round {
635 PropagationRound::Idle => {
636 return Err(PropagationError::RoundNotRunning);
637 },
638 PropagationRound::Running => {},
639 }
640 if !self.inner.all_nodes_updated() {
641 return Err(PropagationError::RoundIncomplete);
642 }
643 let mut carrier = propagation_sentinel();
644 core::mem::swap(&mut self.inner, &mut carrier);
645 carrier.end_round();
646 core::mem::swap(&mut self.inner, &mut carrier);
647 Ok(())
648 }
649
650 pub fn terminate(&mut self) -> (result: Result<(), PropagationError>) {
656 proof { use_type_invariant(&*self); }
657 match self.inner.round {
658 PropagationRound::Running => {
659 return Err(PropagationError::RoundAlreadyRunning);
660 },
661 PropagationRound::Idle => {},
662 }
663 if self.inner.changed && self.inner.iteration != self.inner.max_iterations {
664 return Err(PropagationError::PassStillRunning);
665 }
666 let mut carrier = propagation_sentinel();
667 core::mem::swap(&mut self.inner, &mut carrier);
668 carrier.terminate();
669 core::mem::swap(&mut self.inner, &mut carrier);
670 Ok(())
671 }
672}
673
674#[derive(Clone, Copy, Debug, Eq, PartialEq)]
676#[non_exhaustive]
677pub enum ActuationError {
678 SeatOutOfRange,
680 PassComplete,
682 SeatAlreadyAllocated,
684 SeatUnallocated,
686 SeatAlreadyActuated,
688 PassIncomplete,
690}
691
692pub struct ActuationPass {
709 inner: ActuationPassCarrier,
710}
711
712impl ActuationPass {
713 #[verifier::type_invariant]
714 closed spec fn well_formed(&self) -> bool {
715 self.inner.invariant()
716 }
717
718 pub fn new(allocation: Vec<Option<u64>>) -> (pass: Self) {
720 let num_seats = allocation.len();
721 let inner = ActuationPassCarrier::new(allocation, num_seats);
722 Self { inner }
723 }
724
725 pub fn len(&self) -> usize {
727 self.inner.num_seats
728 }
729
730 pub fn is_empty(&self) -> bool {
732 self.inner.num_seats == 0
733 }
734
735 pub fn is_complete(&self) -> bool {
737 self.inner.complete
738 }
739
740 #[expect(clippy::indexing_slicing, reason = "the branch proves the allocation index is in bounds")]
742 pub fn allocation(&self, seat: usize) -> Option<Option<u64>> {
743 if seat < self.inner.allocation.len() {
744 Some(self.inner.allocation[seat])
745 } else {
746 None
747 }
748 }
749
750 #[expect(clippy::indexing_slicing, reason = "the branch proves the effect index is in bounds")]
752 pub fn effect(&self, seat: usize) -> Option<Option<u64>> {
753 if seat < self.inner.effects.len() {
754 Some(self.inner.effects[seat])
755 } else {
756 None
757 }
758 }
759
760 pub fn allocate(&mut self, seat: usize, resource: u64) -> (result: Result<(), ActuationError>) {
766 proof { use_type_invariant(&*self); }
767 if seat >= self.inner.num_seats {
768 return Err(ActuationError::SeatOutOfRange);
769 }
770 if self.inner.complete {
771 return Err(ActuationError::PassComplete);
772 }
773 if !self.inner.can_allocate(seat) {
774 return Err(ActuationError::SeatAlreadyAllocated);
775 }
776 let mut carrier = actuation_sentinel();
777 core::mem::swap(&mut self.inner, &mut carrier);
778 carrier.allocate(seat, resource);
779 core::mem::swap(&mut self.inner, &mut carrier);
780 Ok(())
781 }
782
783 pub fn deallocate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
789 proof { use_type_invariant(&*self); }
790 if seat >= self.inner.num_seats {
791 return Err(ActuationError::SeatOutOfRange);
792 }
793 if self.inner.complete {
794 return Err(ActuationError::PassComplete);
795 }
796 if !self.inner.is_allocated(seat) {
797 return Err(ActuationError::SeatUnallocated);
798 }
799 if !self.inner.can_deallocate(seat) {
800 return Err(ActuationError::SeatAlreadyActuated);
801 }
802 let mut carrier = actuation_sentinel();
803 core::mem::swap(&mut self.inner, &mut carrier);
804 carrier.deallocate(seat);
805 core::mem::swap(&mut self.inner, &mut carrier);
806 Ok(())
807 }
808
809 pub fn actuate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
815 proof { use_type_invariant(&*self); }
816 if seat >= self.inner.num_seats {
817 return Err(ActuationError::SeatOutOfRange);
818 }
819 if self.inner.complete {
820 return Err(ActuationError::PassComplete);
821 }
822 if !self.inner.is_allocated(seat) {
823 return Err(ActuationError::SeatUnallocated);
824 }
825 if !self.inner.can_actuate(seat) {
826 return Err(ActuationError::SeatAlreadyActuated);
827 }
828 let mut carrier = actuation_sentinel();
829 core::mem::swap(&mut self.inner, &mut carrier);
830 carrier.actuate(seat);
831 core::mem::swap(&mut self.inner, &mut carrier);
832 Ok(())
833 }
834
835 pub fn ready_to_finish(&self) -> (ready: bool) {
837 proof { use_type_invariant(&*self); }
838 self.inner.ready_to_finish_exec()
839 }
840
841 pub fn finish(&mut self) -> (result: Result<(), ActuationError>) {
847 proof { use_type_invariant(&*self); }
848 if self.inner.complete {
849 return Err(ActuationError::PassComplete);
850 }
851 if !self.inner.ready_to_finish_exec() {
852 return Err(ActuationError::PassIncomplete);
853 }
854 let mut carrier = actuation_sentinel();
855 core::mem::swap(&mut self.inner, &mut carrier);
856 carrier.finish();
857 core::mem::swap(&mut self.inner, &mut carrier);
858 Ok(())
859 }
860}
861
862#[derive(Clone, Copy, Debug, Eq, PartialEq)]
864#[non_exhaustive]
865pub enum QualityHierarchyError {
866 NodeOutOfRange,
868 ParentOutOfRange,
870 ChildOutOfRange,
872 LevelOutOfRange,
874 CostOutOfRange,
876 NodeNotIsolated,
878 SelfEdge,
880 EdgeAlreadyExists,
882 ChildAlreadyParented,
884 LevelOrderViolation,
886 CostOrderViolation,
888}
889
890pub struct QualityHierarchy {
905 inner: QualityHierarchyCarrier,
906}
907
908impl QualityHierarchy {
909 #[verifier::type_invariant]
910 closed spec fn well_formed(&self) -> bool {
911 self.inner.type_invariant()
912 && self.inner.strict_level_descent()
913 && self.inner.parent_edge_agreement()
914 && self.inner.cost_monotonicity()
915 }
916
917 pub fn new(num_nodes: usize, max_level: u64) -> (hierarchy: Self) {
919 let inner = QualityHierarchyCarrier::new(num_nodes, max_level);
920 Self { inner }
921 }
922
923 pub fn len(&self) -> usize {
925 self.inner.num_nodes
926 }
927
928 pub fn is_empty(&self) -> bool {
930 self.inner.num_nodes == 0
931 }
932
933 pub fn max_level(&self) -> u64 {
935 self.inner.max_level
936 }
937
938 pub fn level(&self, node: usize) -> Option<u64> {
940 proof { use_type_invariant(&*self); }
941 if node < self.inner.num_nodes {
942 Some(self.inner.level_of(node))
943 } else {
944 None
945 }
946 }
947
948 pub fn cost(&self, node: usize) -> Option<u64> {
950 proof { use_type_invariant(&*self); }
951 if node < self.inner.num_nodes {
952 Some(self.inner.cost_of(node))
953 } else {
954 None
955 }
956 }
957
958 pub fn parent(&self, node: usize) -> Option<usize> {
960 proof { use_type_invariant(&*self); }
961 if node >= self.inner.num_nodes {
962 return None;
963 }
964 let parent = self.inner.parent_of(node);
965 if parent == self.inner.num_nodes {
966 None
967 } else {
968 Some(parent)
969 }
970 }
971
972 pub fn edge_count(&self) -> usize {
974 self.inner.edges.len()
975 }
976
977 #[expect(clippy::indexing_slicing, reason = "the branch proves the hierarchy edge index is in bounds")]
979 pub fn edge(&self, index: usize) -> Option<(usize, usize)> {
980 if index < self.inner.edges.len() {
981 Some(self.inner.edges[index])
982 } else {
983 None
984 }
985 }
986
987 pub fn set_node_properties(
993 &mut self,
994 node: usize,
995 level: u64,
996 cost: u64,
997 ) -> (result: Result<(), QualityHierarchyError>) {
998 proof { use_type_invariant(&*self); }
999 if node >= self.inner.num_nodes {
1000 return Err(QualityHierarchyError::NodeOutOfRange);
1001 }
1002 if level > self.inner.max_level {
1003 return Err(QualityHierarchyError::LevelOutOfRange);
1004 }
1005 if cost > self.inner.max_level {
1006 return Err(QualityHierarchyError::CostOutOfRange);
1007 }
1008 if !self.inner.can_set_node_properties(node, level, cost) {
1009 return Err(QualityHierarchyError::NodeNotIsolated);
1010 }
1011 let mut carrier = quality_hierarchy_sentinel();
1012 core::mem::swap(&mut self.inner, &mut carrier);
1013 carrier.set_node_properties(node, level, cost);
1014 core::mem::swap(&mut self.inner, &mut carrier);
1015 Ok(())
1016 }
1017
1018 pub fn add_child(
1024 &mut self,
1025 parent: usize,
1026 child: usize,
1027 ) -> (result: Result<(), QualityHierarchyError>) {
1028 proof { use_type_invariant(&*self); }
1029 if parent >= self.inner.num_nodes {
1030 return Err(QualityHierarchyError::ParentOutOfRange);
1031 }
1032 if child >= self.inner.num_nodes {
1033 return Err(QualityHierarchyError::ChildOutOfRange);
1034 }
1035 if self.inner.can_add_child(parent, child) {
1036 let mut carrier = quality_hierarchy_sentinel();
1037 core::mem::swap(&mut self.inner, &mut carrier);
1038 carrier.add_child(parent, child);
1039 core::mem::swap(&mut self.inner, &mut carrier);
1040 return Ok(());
1041 }
1042 if parent == child {
1043 Err(QualityHierarchyError::SelfEdge)
1044 } else if self.inner.has_edge(parent, child) {
1045 Err(QualityHierarchyError::EdgeAlreadyExists)
1046 } else if self.inner.parent_of(child) != self.inner.num_nodes {
1047 Err(QualityHierarchyError::ChildAlreadyParented)
1048 } else if self.inner.level_of(parent) <= self.inner.level_of(child) {
1049 Err(QualityHierarchyError::LevelOrderViolation)
1050 } else {
1051 Err(QualityHierarchyError::CostOrderViolation)
1052 }
1053 }
1054}
1055
1056#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1058#[non_exhaustive]
1059pub enum BacktrackingBuildError {
1060 InitialAuxOutOfRange,
1062}
1063
1064#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1066#[non_exhaustive]
1067pub enum BacktrackingError {
1068 AtLeaf,
1070 ChoiceOutOfRange,
1072 DeltaOutOfRange,
1074 NotLeaf,
1076 AlreadyVisited,
1078 AtRoot,
1080}
1081
1082pub struct BacktrackingTraversal {
1097 inner: BacktrackingTraversalCarrier,
1098}
1099
1100impl BacktrackingTraversal {
1101 #[verifier::type_invariant]
1102 closed spec fn well_formed(&self) -> bool {
1103 self.inner.inv()
1104 }
1105
1106 pub fn new(
1112 branch_factor: u64,
1113 max_depth: usize,
1114 initial_aux: u64,
1115 ) -> (result: Result<Self, BacktrackingBuildError>) {
1116 if initial_aux >= 3 {
1117 return Err(BacktrackingBuildError::InitialAuxOutOfRange);
1118 }
1119 let inner = BacktrackingTraversalCarrier::new(branch_factor, max_depth, initial_aux);
1120 Ok(Self { inner })
1121 }
1122
1123 pub fn max_depth(&self) -> usize {
1125 self.inner.max_depth
1126 }
1127
1128 pub fn depth(&self) -> usize {
1130 self.inner.path.len()
1131 }
1132
1133 pub fn auxiliary(&self) -> u64 {
1135 self.inner.aux
1136 }
1137
1138 pub fn visited_count(&self) -> usize {
1140 self.inner.visited.len()
1141 }
1142
1143 pub fn is_leaf(&self) -> bool {
1145 self.inner.is_leaf_exec()
1146 }
1147
1148 #[expect(clippy::indexing_slicing, reason = "the branch proves the path index is in bounds")]
1150 pub fn choice(&self, depth: usize) -> Option<u64> {
1151 if depth < self.inner.path.len() {
1152 Some(self.inner.path[depth])
1153 } else {
1154 None
1155 }
1156 }
1157
1158 pub fn descend(&mut self, choice: u64, delta: u64) -> (result: Result<(), BacktrackingError>) {
1164 proof { use_type_invariant(&*self); }
1165 if self.inner.is_leaf_exec() {
1166 return Err(BacktrackingError::AtLeaf);
1167 }
1168 if choice < 1 || choice > self.inner.branch_factor {
1169 return Err(BacktrackingError::ChoiceOutOfRange);
1170 }
1171 if delta < 1 || delta > 2 {
1172 return Err(BacktrackingError::DeltaOutOfRange);
1173 }
1174 let mut carrier = backtracking_sentinel();
1175 core::mem::swap(&mut self.inner, &mut carrier);
1176 carrier.descend(choice, delta);
1177 core::mem::swap(&mut self.inner, &mut carrier);
1178 Ok(())
1179 }
1180
1181 pub fn visit(&mut self) -> (result: Result<(), BacktrackingError>) {
1187 proof { use_type_invariant(&*self); }
1188 if !self.inner.is_leaf_exec() {
1189 return Err(BacktrackingError::NotLeaf);
1190 }
1191 if !self.inner.can_visit() {
1192 return Err(BacktrackingError::AlreadyVisited);
1193 }
1194 let mut carrier = backtracking_sentinel();
1195 core::mem::swap(&mut self.inner, &mut carrier);
1196 carrier.visit();
1197 core::mem::swap(&mut self.inner, &mut carrier);
1198 Ok(())
1199 }
1200
1201 pub fn ascend(&mut self) -> (result: Result<(), BacktrackingError>) {
1207 proof { use_type_invariant(&*self); }
1208 if !self.inner.can_ascend() {
1209 return Err(BacktrackingError::AtRoot);
1210 }
1211 let mut carrier = backtracking_sentinel();
1212 core::mem::swap(&mut self.inner, &mut carrier);
1213 carrier.ascend();
1214 core::mem::swap(&mut self.inner, &mut carrier);
1215 Ok(())
1216 }
1217}
1218
1219#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1221#[non_exhaustive]
1222pub enum CompetitiveSelectionError {
1223 NoCandidates,
1225 CandidateOutOfRange,
1227 SeatOutOfRange,
1229 SeatAlreadyAllocated,
1231 NoCandidateAvailable,
1233 ScoreOutOfRange,
1235 ScoreCountMismatch,
1237 WeightTotalBelowReservedFloor,
1239 WeightTotalOutOfRange,
1241 MaxScoreOutOfRange,
1243 AllocationComplete,
1245}
1246
1247pub struct CompetitiveSelectionHard {
1261 inner: CompetitiveSelectionHardCarrier,
1262}
1263
1264impl CompetitiveSelectionHard {
1265 #[verifier::type_invariant]
1266 closed spec fn well_formed(&self) -> bool {
1267 self.inner.inv() && self.inner.scores.len() >= 1
1268 }
1269
1270 pub fn new(num_candidates: usize) -> (result: Result<Self, CompetitiveSelectionError>) {
1276 if num_candidates == 0 {
1277 return Err(CompetitiveSelectionError::NoCandidates);
1278 }
1279 let inner = CompetitiveSelectionHardCarrier::new(num_candidates);
1280 Ok(Self { inner })
1281 }
1282
1283 pub fn len(&self) -> usize {
1285 self.inner.scores.len()
1286 }
1287
1288 pub fn is_empty(&self) -> bool {
1290 false
1291 }
1292
1293 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1295 pub fn score(&self, candidate: usize) -> Option<u64> {
1296 if candidate < self.inner.scores.len() {
1297 Some(self.inner.scores[candidate])
1298 } else {
1299 None
1300 }
1301 }
1302
1303 pub fn winner(&self) -> Option<usize> {
1305 self.inner.allocation
1306 }
1307
1308 pub fn update_score(
1314 &mut self,
1315 candidate: usize,
1316 score: u64,
1317 ) -> (result: Result<(), CompetitiveSelectionError>) {
1318 proof { use_type_invariant(&*self); }
1319 if candidate >= self.inner.scores.len() {
1320 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1321 }
1322 let mut carrier = hard_selection_sentinel();
1323 core::mem::swap(&mut self.inner, &mut carrier);
1324 carrier.update_score(candidate, score);
1325 core::mem::swap(&mut self.inner, &mut carrier);
1326 Ok(())
1327 }
1328
1329 #[expect(clippy::manual_unwrap_or_default, reason = "the explicit match is supported by the Verus boundary")]
1331 pub fn evaluate(&mut self) -> (winner: usize) {
1332 proof { use_type_invariant(&*self); }
1333 let mut carrier = hard_selection_sentinel();
1334 core::mem::swap(&mut self.inner, &mut carrier);
1335 carrier.evaluate();
1336 let winner = match carrier.allocation {
1337 Some(value) => value,
1338 None => 0,
1339 };
1340 core::mem::swap(&mut self.inner, &mut carrier);
1341 winner
1342 }
1343}
1344
1345pub struct CompetitiveSelectionHardExclusive {
1360 inner: CompetitiveSelectionHardExclusiveCarrier,
1361}
1362
1363impl CompetitiveSelectionHardExclusive {
1364 #[verifier::type_invariant]
1365 closed spec fn well_formed(&self) -> bool {
1366 self.inner.inv()
1367 }
1368
1369 pub fn new(
1375 num_seats: usize,
1376 num_candidates: usize,
1377 max_score: u64,
1378 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1379 if num_candidates == 0 {
1380 return Err(CompetitiveSelectionError::NoCandidates);
1381 }
1382 let inner = CompetitiveSelectionHardExclusiveCarrier::new(
1383 num_seats,
1384 num_candidates,
1385 max_score,
1386 );
1387 Ok(Self { inner })
1388 }
1389
1390 pub fn seat_count(&self) -> usize {
1392 self.inner.num_seats
1393 }
1394
1395 pub fn candidate_count(&self) -> usize {
1397 self.inner.num_candidates
1398 }
1399
1400 pub fn max_score(&self) -> u64 {
1402 self.inner.max_score
1403 }
1404
1405 #[expect(clippy::indexing_slicing, reason = "the branch proves the seat index is in bounds")]
1407 #[expect(clippy::manual_map, reason = "the explicit match is supported by the Verus boundary")]
1408 pub fn allocation(&self, seat: usize) -> Option<usize> {
1409 proof { use_type_invariant(&*self); }
1410 if seat >= self.inner.num_seats {
1411 return None;
1412 }
1413 match self.inner.allocation[seat] {
1414 Some(candidate) => Some(candidate as usize),
1415 None => None,
1416 }
1417 }
1418
1419 #[expect(clippy::indexing_slicing, reason = "the branches prove both score indices are in bounds")]
1421 pub fn score(&self, seat: usize, candidate: usize) -> Option<u64> {
1422 proof { use_type_invariant(&*self); }
1423 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1424 None
1425 } else {
1426 Some(self.inner.scores[seat][candidate])
1427 }
1428 }
1429
1430 pub fn candidate_available(&self, seat: usize, candidate: usize) -> Option<bool> {
1432 proof { use_type_invariant(&*self); }
1433 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1434 return None;
1435 }
1436 Some(self.inner.candidate_available(seat, candidate))
1437 }
1438
1439 pub fn update_score(
1445 &mut self,
1446 seat: usize,
1447 candidate: usize,
1448 score: u64,
1449 ) -> (result: Result<(), CompetitiveSelectionError>) {
1450 proof { use_type_invariant(&*self); }
1451 if seat >= self.inner.num_seats {
1452 return Err(CompetitiveSelectionError::SeatOutOfRange);
1453 }
1454 if candidate >= self.inner.num_candidates {
1455 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1456 }
1457 if score > self.inner.max_score {
1458 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1459 }
1460 let mut carrier = hard_exclusive_selection_sentinel();
1461 core::mem::swap(&mut self.inner, &mut carrier);
1462 carrier.update_score(seat, candidate, score);
1463 core::mem::swap(&mut self.inner, &mut carrier);
1464 Ok(())
1465 }
1466
1467 #[expect(clippy::indexing_slicing, reason = "the guards prove the seat index is in bounds")]
1473 pub fn evaluate(
1474 &mut self,
1475 seat: usize,
1476 ) -> (result: Result<usize, CompetitiveSelectionError>) {
1477 proof { use_type_invariant(&*self); }
1478 if seat >= self.inner.num_seats {
1479 return Err(CompetitiveSelectionError::SeatOutOfRange);
1480 }
1481 if self.inner.allocation[seat].is_some() {
1482 return Err(CompetitiveSelectionError::SeatAlreadyAllocated);
1483 }
1484 if !self.inner.has_available(seat) {
1485 return Err(CompetitiveSelectionError::NoCandidateAvailable);
1486 }
1487 let mut carrier = hard_exclusive_selection_sentinel();
1488 core::mem::swap(&mut self.inner, &mut carrier);
1489 carrier.evaluate(seat);
1490 let winner = match carrier.allocation[seat] {
1491 Some(candidate) => candidate as usize,
1492 None => 0,
1493 };
1494 core::mem::swap(&mut self.inner, &mut carrier);
1495 Ok(winner)
1496 }
1497}
1498
1499pub struct CompetitiveSelectionSoft {
1511 inner: CompetitiveSelectionSoftCarrier,
1512}
1513
1514impl CompetitiveSelectionSoft {
1515 #[verifier::type_invariant]
1516 closed spec fn well_formed(&self) -> bool {
1517 self.inner.mutable_score_inv()
1518 }
1519
1520 pub fn new(
1526 scores: Vec<u64>,
1527 weight_total: u64,
1528 max_score: u64,
1529 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1530 if scores.is_empty() {
1531 return Err(CompetitiveSelectionError::NoCandidates);
1532 }
1533 if weight_total > 1_000_000_000 {
1534 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1535 }
1536 if max_score > 1_000_000_000 {
1537 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1538 }
1539 if weight_total < scores.len() as u64 {
1540 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1541 }
1542 if !positive_values_within_max(&scores, max_score) {
1543 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1544 }
1545 let inner = CompetitiveSelectionSoftCarrier::new(scores, weight_total, max_score);
1546 Ok(Self { inner })
1547 }
1548
1549 pub fn begin(
1555 scores: Vec<u64>,
1556 weight_total: u64,
1557 max_score: u64,
1558 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1559 if scores.is_empty() {
1560 return Err(CompetitiveSelectionError::NoCandidates);
1561 }
1562 if weight_total > 1_000_000_000 {
1563 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1564 }
1565 if max_score > 1_000_000_000 {
1566 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1567 }
1568 if weight_total < scores.len() as u64 {
1569 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1570 }
1571 if !positive_values_within_max(&scores, max_score) {
1572 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1573 }
1574 let inner = CompetitiveSelectionSoftCarrier::init(scores, weight_total, max_score);
1575 Ok(Self { inner })
1576 }
1577
1578 pub fn len(&self) -> usize {
1580 self.inner.scores.len()
1581 }
1582
1583 pub fn is_empty(&self) -> bool {
1585 false
1586 }
1587
1588 pub fn weight_total(&self) -> u64 {
1590 self.inner.weight_total
1591 }
1592
1593 pub fn max_score(&self) -> u64 {
1595 self.inner.max_score
1596 }
1597
1598 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1600 pub fn score(&self, candidate: usize) -> Option<u64> {
1601 if candidate < self.inner.scores.len() {
1602 Some(self.inner.scores[candidate])
1603 } else {
1604 None
1605 }
1606 }
1607
1608 pub fn weight(&self, candidate: usize) -> Option<u64> {
1610 proof { use_type_invariant(&*self); }
1611 if candidate < self.inner.extra.len() {
1612 Some(self.inner.weight_at(candidate))
1613 } else {
1614 None
1615 }
1616 }
1617
1618 pub fn assigned_weight(&self) -> u64 {
1620 proof { use_type_invariant(&*self); }
1621 self.inner.assigned_weight()
1622 }
1623
1624 pub fn is_complete(&self) -> bool {
1626 self.assigned_weight() == self.inner.weight_total
1627 }
1628
1629 pub fn assign_next(&mut self) -> (result: Result<usize, CompetitiveSelectionError>) {
1635 proof { use_type_invariant(&*self); }
1636 if self.inner.assigned_weight() >= self.inner.weight_total {
1637 return Err(CompetitiveSelectionError::AllocationComplete);
1638 }
1639 let mut carrier = soft_selection_sentinel();
1640 core::mem::swap(&mut self.inner, &mut carrier);
1641 let winner = carrier.assign_next();
1642 core::mem::swap(&mut self.inner, &mut carrier);
1643 Ok(winner)
1644 }
1645
1646 pub fn update_score(
1652 &mut self,
1653 candidate: usize,
1654 score: u64,
1655 ) -> (result: Result<(), CompetitiveSelectionError>) {
1656 proof { use_type_invariant(&*self); }
1657 if candidate >= self.inner.scores.len() {
1658 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1659 }
1660 if score < 1 || score > self.inner.max_score {
1661 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1662 }
1663 let mut carrier = soft_selection_sentinel();
1664 core::mem::swap(&mut self.inner, &mut carrier);
1665 carrier.update_score(candidate, score);
1666 core::mem::swap(&mut self.inner, &mut carrier);
1667 Ok(())
1668 }
1669}
1670
1671pub struct CompetitiveSelectionRanked {
1684 inner: CompetitiveSelectionRankedCarrier,
1685}
1686
1687impl CompetitiveSelectionRanked {
1688 #[verifier::type_invariant]
1689 closed spec fn well_formed(&self) -> bool {
1690 self.inner.inv()
1691 }
1692
1693 pub fn new(
1699 scores: Vec<u64>,
1700 k: usize,
1701 max_score: u64,
1702 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1703 if !values_within_max(&scores, max_score) {
1704 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1705 }
1706 let inner = CompetitiveSelectionRankedCarrier::new(scores, k, max_score);
1707 Ok(Self { inner })
1708 }
1709
1710 pub fn len(&self) -> usize {
1712 self.inner.scores.len()
1713 }
1714
1715 pub fn is_empty(&self) -> bool {
1717 self.inner.scores.is_empty()
1718 }
1719
1720 pub fn limit(&self) -> usize {
1722 self.inner.k
1723 }
1724
1725 pub fn max_score(&self) -> u64 {
1727 self.inner.max_score
1728 }
1729
1730 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1732 pub fn score(&self, candidate: usize) -> Option<u64> {
1733 if candidate < self.inner.scores.len() {
1734 Some(self.inner.scores[candidate])
1735 } else {
1736 None
1737 }
1738 }
1739
1740 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1742 pub fn is_selected(&self, candidate: usize) -> Option<bool> {
1743 if candidate < self.inner.selected.len() {
1744 Some(self.inner.selected[candidate])
1745 } else {
1746 None
1747 }
1748 }
1749
1750 pub fn select(&mut self) {
1752 proof { use_type_invariant(&*self); }
1753 let mut carrier = ranked_selection_sentinel();
1754 core::mem::swap(&mut self.inner, &mut carrier);
1755 carrier.select();
1756 core::mem::swap(&mut self.inner, &mut carrier);
1757 }
1758
1759 pub fn update_scores(
1765 &mut self,
1766 scores: Vec<u64>,
1767 ) -> (result: Result<(), CompetitiveSelectionError>) {
1768 proof { use_type_invariant(&*self); }
1769 if scores.len() != self.inner.scores.len() {
1770 return Err(CompetitiveSelectionError::ScoreCountMismatch);
1771 }
1772 if !values_within_max(&scores, self.inner.max_score) {
1773 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1774 }
1775 let mut carrier = ranked_selection_sentinel();
1776 core::mem::swap(&mut self.inner, &mut carrier);
1777 carrier.update_scores(scores);
1778 core::mem::swap(&mut self.inner, &mut carrier);
1779 Ok(())
1780 }
1781}
1782
1783#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1785#[non_exhaustive]
1786pub enum ConvergenceBuildError {
1787 ThresholdOutOfRange,
1789 EmptyWindow,
1791 WindowSumOutOfRange,
1796}
1797
1798#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1800#[non_exhaustive]
1801pub enum ConvergenceError {
1802 DeltaOutOfRange,
1804}
1805
1806pub struct ConvergenceGovernor {
1819 inner: ConvergenceGovernorCarrier,
1820}
1821
1822impl ConvergenceGovernor {
1823 #[verifier::type_invariant]
1824 closed spec fn well_formed(&self) -> bool {
1825 self.inner.inv()
1826 }
1827
1828 pub fn new(
1837 threshold: u64,
1838 awaken_threshold: u64,
1839 window: usize,
1840 max_delta: u64,
1841 ) -> (result: Result<Self, ConvergenceBuildError>) {
1842 if threshold > u64::MAX / 2 {
1843 return Err(ConvergenceBuildError::ThresholdOutOfRange);
1844 }
1845 if window == 0 {
1846 return Err(ConvergenceBuildError::EmptyWindow);
1847 }
1848 if window > 1_000_000_000 || max_delta > 1_000_000_000 {
1849 return Err(ConvergenceBuildError::WindowSumOutOfRange);
1850 }
1851 proof {
1852 assert(window as int * max_delta as int <= u64::MAX as int) by (nonlinear_arith)
1853 requires
1854 window <= 1_000_000_000,
1855 max_delta <= 1_000_000_000,
1856 u64::MAX >= 1_000_000_000 * 1_000_000_000;
1857 }
1858 let inner = ConvergenceGovernorCarrier::new(
1859 threshold,
1860 awaken_threshold,
1861 window,
1862 max_delta,
1863 );
1864 Ok(Self { inner })
1865 }
1866
1867 pub fn threshold(&self) -> u64 {
1869 self.inner.threshold
1870 }
1871
1872 pub fn awaken_threshold(&self) -> u64 {
1874 self.inner.awaken_threshold
1875 }
1876
1877 pub fn window(&self) -> usize {
1879 self.inner.window
1880 }
1881
1882 pub fn max_delta(&self) -> u64 {
1884 self.inner.max_delta
1885 }
1886
1887 pub fn state(&self) -> ConvergenceState {
1889 self.inner.state
1890 }
1891
1892 pub fn phase(&self) -> ConvergencePhase {
1894 self.inner.gradient_phase
1895 }
1896
1897 pub fn peak_observed(&self) -> bool {
1899 self.inner.peak_observed
1900 }
1901
1902 pub fn history_len(&self) -> usize {
1904 self.inner.delta_history.len()
1905 }
1906
1907 #[expect(clippy::indexing_slicing, reason = "the branch proves the history index is in bounds")]
1909 pub fn history(&self, index: usize) -> Option<u64> {
1910 if index < self.inner.delta_history.len() {
1911 Some(self.inner.delta_history[index])
1912 } else {
1913 None
1914 }
1915 }
1916
1917 pub fn update(&mut self, delta: u64) -> (result: Result<u64, ConvergenceError>) {
1923 proof { use_type_invariant(&*self); }
1924 if delta > self.inner.max_delta {
1925 return Err(ConvergenceError::DeltaOutOfRange);
1926 }
1927 let mut carrier = convergence_sentinel();
1928 core::mem::swap(&mut self.inner, &mut carrier);
1929 let average = carrier.update(delta);
1930 core::mem::swap(&mut self.inner, &mut carrier);
1931 Ok(average)
1932 }
1933}
1934
1935fn budget_sentinel() -> (carrier: BudgetCarrier)
1936 ensures carrier.safety_invariant(),
1937{
1938 BudgetCarrier::new(0)
1939}
1940
1941fn registry_sentinel() -> (carrier: RegistryCarrier<u64, u64>)
1942 ensures carrier.unique_mapping(),
1943{
1944 RegistryCarrier::new()
1945}
1946
1947fn audit_sentinel() -> (carrier: AuditSinkCarrier)
1948 ensures carrier.inv(),
1949{
1950 AuditSinkCarrier::new(0)
1951}
1952
1953fn propagation_sentinel() -> (carrier: PropagationPassCarrier)
1954 ensures carrier.inv(),
1955{
1956 let edges: Vec<(usize, usize)> = Vec::new();
1957 let values: Vec<u64> = Vec::new();
1958 PropagationPassCarrier::new(0, 0, 0, edges, values)
1959}
1960
1961fn actuation_sentinel() -> (carrier: ActuationPassCarrier)
1962 ensures carrier.invariant(),
1963{
1964 let allocation: Vec<Option<u64>> = Vec::new();
1965 ActuationPassCarrier::new(allocation, 0)
1966}
1967
1968fn quality_hierarchy_sentinel() -> (carrier: QualityHierarchyCarrier)
1969 ensures
1970 carrier.type_invariant(),
1971 carrier.strict_level_descent(),
1972 carrier.parent_edge_agreement(),
1973 carrier.cost_monotonicity(),
1974{
1975 QualityHierarchyCarrier::new(0, 0)
1976}
1977
1978fn backtracking_sentinel() -> (carrier: BacktrackingTraversalCarrier)
1979 ensures carrier.inv(),
1980{
1981 BacktrackingTraversalCarrier::new(0, 0, 0)
1982}
1983
1984fn hard_selection_sentinel() -> (carrier: CompetitiveSelectionHardCarrier)
1985 ensures
1986 carrier.inv(),
1987 carrier.scores.len() >= 1,
1988{
1989 CompetitiveSelectionHardCarrier::new(1)
1990}
1991
1992fn hard_exclusive_selection_sentinel() -> (carrier: CompetitiveSelectionHardExclusiveCarrier)
1993 ensures carrier.inv(),
1994{
1995 CompetitiveSelectionHardExclusiveCarrier::new(0, 1, 0)
1996}
1997
1998fn soft_selection_sentinel() -> (carrier: CompetitiveSelectionSoftCarrier)
1999 ensures carrier.mutable_score_inv(),
2000{
2001 let mut scores: Vec<u64> = Vec::new();
2002 scores.push(1);
2003 CompetitiveSelectionSoftCarrier::init(scores, 1, 1)
2004}
2005
2006fn ranked_selection_sentinel() -> (carrier: CompetitiveSelectionRankedCarrier)
2007 ensures carrier.inv(),
2008{
2009 let scores: Vec<u64> = Vec::new();
2010 CompetitiveSelectionRankedCarrier::new(scores, 0, 0)
2011}
2012
2013fn convergence_sentinel() -> (carrier: ConvergenceGovernorCarrier)
2014 ensures carrier.inv(),
2015{
2016 ConvergenceGovernorCarrier::new(0, 0, 1, 0)
2017}
2018
2019#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2020#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2021#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2022pub(crate) fn values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2023 ensures
2024 valid == (forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value),
2025{
2026 let mut index: usize = 0;
2027 while index < values.len()
2028 invariant
2029 index <= values.len(),
2030 forall|i: int| 0 <= i < index ==> values@[i] <= max_value,
2031 decreases values.len() - index,
2032 {
2033 if values[index] > max_value {
2034 assert(!(forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value));
2035 return false;
2036 }
2037 index += 1;
2038 }
2039 true
2040}
2041
2042#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2043#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2044#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2045fn positive_values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2046 ensures
2047 valid == (forall|i: int| 0 <= i < values.len()
2048 ==> 1 <= #[trigger] values@[i] <= max_value),
2049{
2050 let mut index: usize = 0;
2051 while index < values.len()
2052 invariant
2053 index <= values.len(),
2054 forall|i: int| 0 <= i < index ==> 1 <= #[trigger] values@[i] <= max_value,
2055 decreases values.len() - index,
2056 {
2057 if values[index] < 1 || values[index] > max_value {
2058 assert(!(forall|i: int| 0 <= i < values.len()
2059 ==> 1 <= #[trigger] values@[i] <= max_value));
2060 return false;
2061 }
2062 index += 1;
2063 }
2064 true
2065}
2066
2067#[expect(clippy::indexing_slicing, reason = "the loop proves the edge index is in bounds")]
2068#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2069#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2070fn edges_within_nodes(edges: &Vec<(usize, usize)>, num_nodes: usize) -> (valid: bool)
2071 ensures
2072 valid == (forall|i: int| 0 <= i < edges.len()
2073 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes),
2074{
2075 let mut index: usize = 0;
2076 while index < edges.len()
2077 invariant
2078 index <= edges.len(),
2079 forall|i: int| 0 <= i < index
2080 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes,
2081 decreases edges.len() - index,
2082 {
2083 if edges[index].0 >= num_nodes || edges[index].1 >= num_nodes {
2084 assert(!(forall|i: int| 0 <= i < edges.len()
2085 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes));
2086 return false;
2087 }
2088 index += 1;
2089 }
2090 true
2091}
2092
2093} impl Budget {
2096 pub fn is_empty(&self) -> bool {
2098 self.allocated() == 0 && self.reserved() == 0 && self.pending_eviction() == 0
2099 }
2100
2101 pub fn is_full(&self) -> bool {
2103 self.available() == 0
2104 }
2105}
2106
2107impl ResourceRegistry {
2108 pub fn contains_key(&self, key: u64) -> bool {
2110 self.get(key).is_some()
2111 }
2112
2113 pub fn iter(&self) -> impl ExactSizeIterator<Item = &(u64, u64)> {
2115 self.inner.entries.iter()
2116 }
2117}
2118
2119impl AuditSink {
2120 pub fn is_full(&self) -> bool {
2122 self.len() == self.capacity()
2123 }
2124
2125 pub fn records(&self) -> impl ExactSizeIterator<Item = AuditRecord> + '_ {
2127 self.inner.log.iter().map(|entry| AuditRecord {
2128 operation: entry.operation,
2129 previous_hash: entry.prev_hash,
2130 hash: entry.hash,
2131 })
2132 }
2133}
2134
2135impl PropagationPass {
2136 pub fn edges(&self) -> &[(usize, usize)] {
2138 self.inner.edges.as_slice()
2139 }
2140
2141 pub fn values(&self) -> &[u64] {
2143 self.inner.values.as_slice()
2144 }
2145
2146 pub fn snapshot_values(&self) -> &[u64] {
2148 self.inner.snapshot.as_slice()
2149 }
2150
2151 pub fn updated_nodes(&self) -> &[bool] {
2153 self.inner.updated.as_slice()
2154 }
2155}
2156
2157impl ActuationPass {
2158 pub fn allocations(&self) -> &[Option<u64>] {
2160 self.inner.allocation.as_slice()
2161 }
2162
2163 pub fn effects(&self) -> &[Option<u64>] {
2165 self.inner.effects.as_slice()
2166 }
2167}
2168
2169impl QualityHierarchy {
2170 pub fn levels(&self) -> &[u64] {
2172 self.inner.level.as_slice()
2173 }
2174
2175 pub fn costs(&self) -> &[u64] {
2177 self.inner.cost.as_slice()
2178 }
2179
2180 pub fn encoded_parents(&self) -> &[usize] {
2184 self.inner.parent.as_slice()
2185 }
2186
2187 pub fn edges(&self) -> &[(usize, usize)] {
2189 self.inner.edges.as_slice()
2190 }
2191
2192 pub fn has_children(&self, node: usize) -> Option<bool> {
2194 (node < self.len()).then(|| self.inner.has_children(node))
2195 }
2196
2197 pub fn has_edge(&self, parent: usize, child: usize) -> Option<bool> {
2199 (parent < self.len() && child < self.len()).then(|| self.inner.has_edge(parent, child))
2200 }
2201}
2202
2203impl BacktrackingTraversal {
2204 pub fn branch_factor(&self) -> u64 {
2206 self.inner.branch_factor
2207 }
2208
2209 pub fn initial_auxiliary(&self) -> u64 {
2211 self.inner.init_aux
2212 }
2213
2214 pub fn choices(&self) -> &[u64] {
2216 self.inner.path.as_slice()
2217 }
2218
2219 pub fn visited_paths(&self) -> impl ExactSizeIterator<Item = &[u64]> {
2221 self.inner.visited.iter().map(Vec::as_slice)
2222 }
2223}
2224
2225impl CompetitiveSelectionHard {
2226 pub fn scores(&self) -> &[u64] {
2228 self.inner.scores.as_slice()
2229 }
2230}
2231
2232impl CompetitiveSelectionHardExclusive {
2233 pub fn is_empty(&self) -> bool {
2235 self.seat_count() == 0
2236 }
2237
2238 pub fn allocations(&self) -> &[Option<u64>] {
2240 self.inner.allocation.as_slice()
2241 }
2242
2243 pub fn scores(&self, seat: usize) -> Option<&[u64]> {
2245 self.inner.scores.get(seat).map(Vec::as_slice)
2246 }
2247}
2248
2249impl CompetitiveSelectionSoft {
2250 pub fn scores(&self) -> &[u64] {
2252 self.inner.scores.as_slice()
2253 }
2254
2255 pub fn weights(&self) -> impl ExactSizeIterator<Item = u64> + '_ {
2257 self.inner.extra.iter().map(|extra| extra + 1)
2258 }
2259}
2260
2261impl CompetitiveSelectionRanked {
2262 pub fn scores(&self) -> &[u64] {
2264 self.inner.scores.as_slice()
2265 }
2266
2267 pub fn selections(&self) -> &[bool] {
2269 self.inner.selected.as_slice()
2270 }
2271
2272 pub fn selected_len(&self) -> usize {
2274 self.inner
2275 .selected
2276 .iter()
2277 .filter(|selected| **selected)
2278 .count()
2279 }
2280}
2281
2282impl ConvergenceGovernor {
2283 pub fn history_values(&self) -> &[u64] {
2285 self.inner.delta_history.as_slice()
2286 }
2287}
2288
2289impl Default for ResourceRegistry {
2290 fn default() -> Self {
2291 Self::new()
2292 }
2293}
2294
2295impl_observational_debug!(Budget, "Budget",
2296 "capacity" => capacity,
2297 "allocated" => allocated,
2298 "reserved" => reserved,
2299 "pending_eviction" => pending_eviction,
2300 "available" => available,
2301);
2302impl_observational_debug!(ResourceRegistry, "ResourceRegistry", "len" => len);
2303impl_observational_debug!(AuditSink, "AuditSink",
2304 "capacity" => capacity,
2305 "len" => len,
2306 "last_hash" => last_hash,
2307 "valid" => validate,
2308);
2309impl_observational_debug!(Cursor, "Cursor", "position" => position);
2310impl_observational_debug!(PropagationPass, "PropagationPass",
2311 "num_nodes" => num_nodes,
2312 "max_iterations" => max_iterations,
2313 "iteration" => iteration,
2314 "round" => round,
2315 "changed" => changed,
2316);
2317impl_observational_debug!(ActuationPass, "ActuationPass",
2318 "len" => len,
2319 "complete" => is_complete,
2320 "ready_to_finish" => ready_to_finish,
2321);
2322impl_observational_debug!(QualityHierarchy, "QualityHierarchy",
2323 "len" => len,
2324 "max_level" => max_level,
2325 "edge_count" => edge_count,
2326);
2327impl_observational_debug!(BacktrackingTraversal, "BacktrackingTraversal",
2328 "max_depth" => max_depth,
2329 "depth" => depth,
2330 "auxiliary" => auxiliary,
2331 "visited_count" => visited_count,
2332 "leaf" => is_leaf,
2333);
2334impl_observational_debug!(CompetitiveSelectionHard, "CompetitiveSelectionHard",
2335 "len" => len,
2336 "winner" => winner,
2337);
2338impl_observational_debug!(CompetitiveSelectionHardExclusive, "CompetitiveSelectionHardExclusive",
2339 "seat_count" => seat_count,
2340 "candidate_count" => candidate_count,
2341 "max_score" => max_score,
2342);
2343impl_observational_debug!(CompetitiveSelectionSoft, "CompetitiveSelectionSoft",
2344 "len" => len,
2345 "weight_total" => weight_total,
2346 "assigned_weight" => assigned_weight,
2347 "max_score" => max_score,
2348 "complete" => is_complete,
2349);
2350impl_observational_debug!(CompetitiveSelectionRanked, "CompetitiveSelectionRanked",
2351 "len" => len,
2352 "limit" => limit,
2353 "max_score" => max_score,
2354);
2355impl_observational_debug!(ConvergenceGovernor, "ConvergenceGovernor",
2356 "threshold" => threshold,
2357 "awaken_threshold" => awaken_threshold,
2358 "window" => window,
2359 "max_delta" => max_delta,
2360 "state" => state,
2361 "phase" => phase,
2362 "peak_observed" => peak_observed,
2363 "history_len" => history_len,
2364);
2365
2366impl_public_error!(BudgetError, {
2367 Self::AmountExceedsReservation => "amount exceeds the held reservation",
2368 Self::AmountExceedsAllocation => "amount exceeds the committed allocation",
2369 Self::AmountExceedsPendingEviction => "amount exceeds pending eviction",
2370});
2371impl_public_error!(CursorError, {
2372 Self::Regression => "cursor movement would regress the retained position",
2373});
2374impl_public_error!(PropagationBuildError, {
2375 Self::InitialValueOutOfRange => "an initial value exceeds the declared value ceiling",
2376 Self::EdgeEndpointOutOfRange => "an edge endpoint is outside the admitted node set",
2377});
2378impl_public_error!(PropagationError, {
2379 Self::NodeOutOfRange => "node is outside the admitted graph",
2380 Self::RoundAlreadyRunning => "a propagation round is already running",
2381 Self::RoundNotRunning => "no propagation round is running",
2382 Self::NodeAlreadyUpdated => "node already committed an update in this round",
2383 Self::RoundIncomplete => "not every node committed an update",
2384 Self::PassTerminated => "propagation pass is settled or exhausted",
2385 Self::PassStillRunning => "propagation pass has not reached a terminal state",
2386});
2387impl_public_error!(ActuationError, {
2388 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2389 Self::PassComplete => "actuation pass is already complete",
2390 Self::SeatAlreadyAllocated => "seat already holds a resource",
2391 Self::SeatUnallocated => "seat holds no resource",
2392 Self::SeatAlreadyActuated => "seat already committed its effect",
2393 Self::PassIncomplete => "an allocated seat has not committed its effect",
2394});
2395impl_public_error!(QualityHierarchyError, {
2396 Self::NodeOutOfRange => "node is outside the admitted hierarchy",
2397 Self::ParentOutOfRange => "parent is outside the admitted hierarchy",
2398 Self::ChildOutOfRange => "child is outside the admitted hierarchy",
2399 Self::LevelOutOfRange => "level exceeds the hierarchy ceiling",
2400 Self::CostOutOfRange => "cost exceeds the hierarchy ceiling",
2401 Self::NodeNotIsolated => "node properties may change only while the node is isolated",
2402 Self::SelfEdge => "a hierarchy node cannot be its own child",
2403 Self::EdgeAlreadyExists => "the parent-child edge already exists",
2404 Self::ChildAlreadyParented => "the child already has a parent",
2405 Self::LevelOrderViolation => "parent level must strictly exceed child level",
2406 Self::CostOrderViolation => "parent cost must not exceed child cost",
2407});
2408impl_public_error!(BacktrackingBuildError, {
2409 Self::InitialAuxOutOfRange => "initial auxiliary value is outside the modulo-three domain",
2410});
2411impl_public_error!(BacktrackingError, {
2412 Self::AtLeaf => "descent is disabled at a leaf",
2413 Self::ChoiceOutOfRange => "branch choice is outside the admitted branch set",
2414 Self::DeltaOutOfRange => "mutation delta must be one or two",
2415 Self::NotLeaf => "visit requires a full-depth leaf",
2416 Self::AlreadyVisited => "the current leaf was already visited",
2417 Self::AtRoot => "ascent is disabled at the root",
2418});
2419impl_public_error!(CompetitiveSelectionError, {
2420 Self::NoCandidates => "at least one candidate is required",
2421 Self::CandidateOutOfRange => "candidate is outside the admitted candidate set",
2422 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2423 Self::SeatAlreadyAllocated => "seat already holds an allocation",
2424 Self::NoCandidateAvailable => "no candidate is available for the seat",
2425 Self::ScoreOutOfRange => "score is outside the admitted score domain",
2426 Self::ScoreCountMismatch => "replacement scores have a different candidate count",
2427 Self::WeightTotalBelowReservedFloor => "weight total is smaller than the reserved candidate floor",
2428 Self::WeightTotalOutOfRange => "weight total exceeds the verified arithmetic ceiling",
2429 Self::MaxScoreOutOfRange => "maximum score exceeds the verified arithmetic ceiling",
2430 Self::AllocationComplete => "all soft-selection weight has been assigned",
2431});
2432impl_public_error!(ConvergenceBuildError, {
2433 Self::ThresholdOutOfRange => "convergence threshold cannot be doubled safely",
2434 Self::EmptyWindow => "convergence history window must be nonempty",
2435 Self::WindowSumOutOfRange => "convergence window or maximum delta exceeds one billion",
2436});
2437impl_public_error!(ConvergenceError, {
2438 Self::DeltaOutOfRange => "delta exceeds the configured maximum",
2439});