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,
1793}
1794
1795#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1797#[non_exhaustive]
1798pub enum ConvergenceError {
1799 DeltaOutOfRange,
1801}
1802
1803pub struct ConvergenceGovernor {
1816 inner: ConvergenceGovernorCarrier,
1817}
1818
1819impl ConvergenceGovernor {
1820 #[verifier::type_invariant]
1821 closed spec fn well_formed(&self) -> bool {
1822 self.inner.inv()
1823 }
1824
1825 pub fn new(
1831 threshold: u64,
1832 awaken_threshold: u64,
1833 window: usize,
1834 max_delta: u64,
1835 ) -> (result: Result<Self, ConvergenceBuildError>) {
1836 if threshold > u64::MAX / 2 {
1837 return Err(ConvergenceBuildError::ThresholdOutOfRange);
1838 }
1839 if window == 0 {
1840 return Err(ConvergenceBuildError::EmptyWindow);
1841 }
1842 if window > 1_000_000_000 || max_delta > 1_000_000_000 {
1843 return Err(ConvergenceBuildError::WindowSumOutOfRange);
1844 }
1845 proof {
1846 assert(window as int * max_delta as int <= u64::MAX as int) by (nonlinear_arith)
1847 requires
1848 window <= 1_000_000_000,
1849 max_delta <= 1_000_000_000,
1850 u64::MAX >= 1_000_000_000 * 1_000_000_000;
1851 }
1852 let inner = ConvergenceGovernorCarrier::new(
1853 threshold,
1854 awaken_threshold,
1855 window,
1856 max_delta,
1857 );
1858 Ok(Self { inner })
1859 }
1860
1861 pub fn threshold(&self) -> u64 {
1863 self.inner.threshold
1864 }
1865
1866 pub fn awaken_threshold(&self) -> u64 {
1868 self.inner.awaken_threshold
1869 }
1870
1871 pub fn window(&self) -> usize {
1873 self.inner.window
1874 }
1875
1876 pub fn max_delta(&self) -> u64 {
1878 self.inner.max_delta
1879 }
1880
1881 pub fn state(&self) -> ConvergenceState {
1883 self.inner.state
1884 }
1885
1886 pub fn phase(&self) -> ConvergencePhase {
1888 self.inner.gradient_phase
1889 }
1890
1891 pub fn peak_observed(&self) -> bool {
1893 self.inner.peak_observed
1894 }
1895
1896 pub fn history_len(&self) -> usize {
1898 self.inner.delta_history.len()
1899 }
1900
1901 #[expect(clippy::indexing_slicing, reason = "the branch proves the history index is in bounds")]
1903 pub fn history(&self, index: usize) -> Option<u64> {
1904 if index < self.inner.delta_history.len() {
1905 Some(self.inner.delta_history[index])
1906 } else {
1907 None
1908 }
1909 }
1910
1911 pub fn update(&mut self, delta: u64) -> (result: Result<u64, ConvergenceError>) {
1917 proof { use_type_invariant(&*self); }
1918 if delta > self.inner.max_delta {
1919 return Err(ConvergenceError::DeltaOutOfRange);
1920 }
1921 let mut carrier = convergence_sentinel();
1922 core::mem::swap(&mut self.inner, &mut carrier);
1923 let average = carrier.update(delta);
1924 core::mem::swap(&mut self.inner, &mut carrier);
1925 Ok(average)
1926 }
1927}
1928
1929fn budget_sentinel() -> (carrier: BudgetCarrier)
1930 ensures carrier.safety_invariant(),
1931{
1932 BudgetCarrier::new(0)
1933}
1934
1935fn registry_sentinel() -> (carrier: RegistryCarrier<u64, u64>)
1936 ensures carrier.unique_mapping(),
1937{
1938 RegistryCarrier::new()
1939}
1940
1941fn audit_sentinel() -> (carrier: AuditSinkCarrier)
1942 ensures carrier.inv(),
1943{
1944 AuditSinkCarrier::new(0)
1945}
1946
1947fn propagation_sentinel() -> (carrier: PropagationPassCarrier)
1948 ensures carrier.inv(),
1949{
1950 let edges: Vec<(usize, usize)> = Vec::new();
1951 let values: Vec<u64> = Vec::new();
1952 PropagationPassCarrier::new(0, 0, 0, edges, values)
1953}
1954
1955fn actuation_sentinel() -> (carrier: ActuationPassCarrier)
1956 ensures carrier.invariant(),
1957{
1958 let allocation: Vec<Option<u64>> = Vec::new();
1959 ActuationPassCarrier::new(allocation, 0)
1960}
1961
1962fn quality_hierarchy_sentinel() -> (carrier: QualityHierarchyCarrier)
1963 ensures
1964 carrier.type_invariant(),
1965 carrier.strict_level_descent(),
1966 carrier.parent_edge_agreement(),
1967 carrier.cost_monotonicity(),
1968{
1969 QualityHierarchyCarrier::new(0, 0)
1970}
1971
1972fn backtracking_sentinel() -> (carrier: BacktrackingTraversalCarrier)
1973 ensures carrier.inv(),
1974{
1975 BacktrackingTraversalCarrier::new(0, 0, 0)
1976}
1977
1978fn hard_selection_sentinel() -> (carrier: CompetitiveSelectionHardCarrier)
1979 ensures
1980 carrier.inv(),
1981 carrier.scores.len() >= 1,
1982{
1983 CompetitiveSelectionHardCarrier::new(1)
1984}
1985
1986fn hard_exclusive_selection_sentinel() -> (carrier: CompetitiveSelectionHardExclusiveCarrier)
1987 ensures carrier.inv(),
1988{
1989 CompetitiveSelectionHardExclusiveCarrier::new(0, 1, 0)
1990}
1991
1992fn soft_selection_sentinel() -> (carrier: CompetitiveSelectionSoftCarrier)
1993 ensures carrier.mutable_score_inv(),
1994{
1995 let mut scores: Vec<u64> = Vec::new();
1996 scores.push(1);
1997 CompetitiveSelectionSoftCarrier::init(scores, 1, 1)
1998}
1999
2000fn ranked_selection_sentinel() -> (carrier: CompetitiveSelectionRankedCarrier)
2001 ensures carrier.inv(),
2002{
2003 let scores: Vec<u64> = Vec::new();
2004 CompetitiveSelectionRankedCarrier::new(scores, 0, 0)
2005}
2006
2007fn convergence_sentinel() -> (carrier: ConvergenceGovernorCarrier)
2008 ensures carrier.inv(),
2009{
2010 ConvergenceGovernorCarrier::new(0, 0, 1, 0)
2011}
2012
2013#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2014#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2015#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2016pub(crate) fn values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2017 ensures
2018 valid == (forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value),
2019{
2020 let mut index: usize = 0;
2021 while index < values.len()
2022 invariant
2023 index <= values.len(),
2024 forall|i: int| 0 <= i < index ==> values@[i] <= max_value,
2025 decreases values.len() - index,
2026 {
2027 if values[index] > max_value {
2028 assert(!(forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value));
2029 return false;
2030 }
2031 index += 1;
2032 }
2033 true
2034}
2035
2036#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2037#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2038#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2039fn positive_values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2040 ensures
2041 valid == (forall|i: int| 0 <= i < values.len()
2042 ==> 1 <= #[trigger] values@[i] <= max_value),
2043{
2044 let mut index: usize = 0;
2045 while index < values.len()
2046 invariant
2047 index <= values.len(),
2048 forall|i: int| 0 <= i < index ==> 1 <= #[trigger] values@[i] <= max_value,
2049 decreases values.len() - index,
2050 {
2051 if values[index] < 1 || values[index] > max_value {
2052 assert(!(forall|i: int| 0 <= i < values.len()
2053 ==> 1 <= #[trigger] values@[i] <= max_value));
2054 return false;
2055 }
2056 index += 1;
2057 }
2058 true
2059}
2060
2061#[expect(clippy::indexing_slicing, reason = "the loop proves the edge index is in bounds")]
2062#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2063#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2064fn edges_within_nodes(edges: &Vec<(usize, usize)>, num_nodes: usize) -> (valid: bool)
2065 ensures
2066 valid == (forall|i: int| 0 <= i < edges.len()
2067 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes),
2068{
2069 let mut index: usize = 0;
2070 while index < edges.len()
2071 invariant
2072 index <= edges.len(),
2073 forall|i: int| 0 <= i < index
2074 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes,
2075 decreases edges.len() - index,
2076 {
2077 if edges[index].0 >= num_nodes || edges[index].1 >= num_nodes {
2078 assert(!(forall|i: int| 0 <= i < edges.len()
2079 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes));
2080 return false;
2081 }
2082 index += 1;
2083 }
2084 true
2085}
2086
2087} impl Budget {
2090 pub fn is_empty(&self) -> bool {
2092 self.allocated() == 0 && self.reserved() == 0 && self.pending_eviction() == 0
2093 }
2094
2095 pub fn is_full(&self) -> bool {
2097 self.available() == 0
2098 }
2099}
2100
2101impl ResourceRegistry {
2102 pub fn contains_key(&self, key: u64) -> bool {
2104 self.get(key).is_some()
2105 }
2106
2107 pub fn iter(&self) -> impl ExactSizeIterator<Item = &(u64, u64)> {
2109 self.inner.entries.iter()
2110 }
2111}
2112
2113impl AuditSink {
2114 pub fn is_full(&self) -> bool {
2116 self.len() == self.capacity()
2117 }
2118
2119 pub fn records(&self) -> impl ExactSizeIterator<Item = AuditRecord> + '_ {
2121 self.inner.log.iter().map(|entry| AuditRecord {
2122 operation: entry.operation,
2123 previous_hash: entry.prev_hash,
2124 hash: entry.hash,
2125 })
2126 }
2127}
2128
2129impl PropagationPass {
2130 pub fn edges(&self) -> &[(usize, usize)] {
2132 self.inner.edges.as_slice()
2133 }
2134
2135 pub fn values(&self) -> &[u64] {
2137 self.inner.values.as_slice()
2138 }
2139
2140 pub fn snapshot_values(&self) -> &[u64] {
2142 self.inner.snapshot.as_slice()
2143 }
2144
2145 pub fn updated_nodes(&self) -> &[bool] {
2147 self.inner.updated.as_slice()
2148 }
2149}
2150
2151impl ActuationPass {
2152 pub fn allocations(&self) -> &[Option<u64>] {
2154 self.inner.allocation.as_slice()
2155 }
2156
2157 pub fn effects(&self) -> &[Option<u64>] {
2159 self.inner.effects.as_slice()
2160 }
2161}
2162
2163impl QualityHierarchy {
2164 pub fn levels(&self) -> &[u64] {
2166 self.inner.level.as_slice()
2167 }
2168
2169 pub fn costs(&self) -> &[u64] {
2171 self.inner.cost.as_slice()
2172 }
2173
2174 pub fn encoded_parents(&self) -> &[usize] {
2178 self.inner.parent.as_slice()
2179 }
2180
2181 pub fn edges(&self) -> &[(usize, usize)] {
2183 self.inner.edges.as_slice()
2184 }
2185
2186 pub fn has_children(&self, node: usize) -> Option<bool> {
2188 (node < self.len()).then(|| self.inner.has_children(node))
2189 }
2190
2191 pub fn has_edge(&self, parent: usize, child: usize) -> Option<bool> {
2193 (parent < self.len() && child < self.len()).then(|| self.inner.has_edge(parent, child))
2194 }
2195}
2196
2197impl BacktrackingTraversal {
2198 pub fn branch_factor(&self) -> u64 {
2200 self.inner.branch_factor
2201 }
2202
2203 pub fn initial_auxiliary(&self) -> u64 {
2205 self.inner.init_aux
2206 }
2207
2208 pub fn choices(&self) -> &[u64] {
2210 self.inner.path.as_slice()
2211 }
2212
2213 pub fn visited_paths(&self) -> impl ExactSizeIterator<Item = &[u64]> {
2215 self.inner.visited.iter().map(Vec::as_slice)
2216 }
2217}
2218
2219impl CompetitiveSelectionHard {
2220 pub fn scores(&self) -> &[u64] {
2222 self.inner.scores.as_slice()
2223 }
2224}
2225
2226impl CompetitiveSelectionHardExclusive {
2227 pub fn is_empty(&self) -> bool {
2229 self.seat_count() == 0
2230 }
2231
2232 pub fn allocations(&self) -> &[Option<u64>] {
2234 self.inner.allocation.as_slice()
2235 }
2236
2237 pub fn scores(&self, seat: usize) -> Option<&[u64]> {
2239 self.inner.scores.get(seat).map(Vec::as_slice)
2240 }
2241}
2242
2243impl CompetitiveSelectionSoft {
2244 pub fn scores(&self) -> &[u64] {
2246 self.inner.scores.as_slice()
2247 }
2248
2249 pub fn weights(&self) -> impl ExactSizeIterator<Item = u64> + '_ {
2251 self.inner.extra.iter().map(|extra| extra + 1)
2252 }
2253}
2254
2255impl CompetitiveSelectionRanked {
2256 pub fn scores(&self) -> &[u64] {
2258 self.inner.scores.as_slice()
2259 }
2260
2261 pub fn selections(&self) -> &[bool] {
2263 self.inner.selected.as_slice()
2264 }
2265
2266 pub fn selected_len(&self) -> usize {
2268 self.inner
2269 .selected
2270 .iter()
2271 .filter(|selected| **selected)
2272 .count()
2273 }
2274}
2275
2276impl ConvergenceGovernor {
2277 pub fn history_values(&self) -> &[u64] {
2279 self.inner.delta_history.as_slice()
2280 }
2281}
2282
2283impl Default for ResourceRegistry {
2284 fn default() -> Self {
2285 Self::new()
2286 }
2287}
2288
2289impl_observational_debug!(Budget, "Budget",
2290 "capacity" => capacity,
2291 "allocated" => allocated,
2292 "reserved" => reserved,
2293 "pending_eviction" => pending_eviction,
2294 "available" => available,
2295);
2296impl_observational_debug!(ResourceRegistry, "ResourceRegistry", "len" => len);
2297impl_observational_debug!(AuditSink, "AuditSink",
2298 "capacity" => capacity,
2299 "len" => len,
2300 "last_hash" => last_hash,
2301 "valid" => validate,
2302);
2303impl_observational_debug!(Cursor, "Cursor", "position" => position);
2304impl_observational_debug!(PropagationPass, "PropagationPass",
2305 "num_nodes" => num_nodes,
2306 "max_iterations" => max_iterations,
2307 "iteration" => iteration,
2308 "round" => round,
2309 "changed" => changed,
2310);
2311impl_observational_debug!(ActuationPass, "ActuationPass",
2312 "len" => len,
2313 "complete" => is_complete,
2314 "ready_to_finish" => ready_to_finish,
2315);
2316impl_observational_debug!(QualityHierarchy, "QualityHierarchy",
2317 "len" => len,
2318 "max_level" => max_level,
2319 "edge_count" => edge_count,
2320);
2321impl_observational_debug!(BacktrackingTraversal, "BacktrackingTraversal",
2322 "max_depth" => max_depth,
2323 "depth" => depth,
2324 "auxiliary" => auxiliary,
2325 "visited_count" => visited_count,
2326 "leaf" => is_leaf,
2327);
2328impl_observational_debug!(CompetitiveSelectionHard, "CompetitiveSelectionHard",
2329 "len" => len,
2330 "winner" => winner,
2331);
2332impl_observational_debug!(CompetitiveSelectionHardExclusive, "CompetitiveSelectionHardExclusive",
2333 "seat_count" => seat_count,
2334 "candidate_count" => candidate_count,
2335 "max_score" => max_score,
2336);
2337impl_observational_debug!(CompetitiveSelectionSoft, "CompetitiveSelectionSoft",
2338 "len" => len,
2339 "weight_total" => weight_total,
2340 "assigned_weight" => assigned_weight,
2341 "max_score" => max_score,
2342 "complete" => is_complete,
2343);
2344impl_observational_debug!(CompetitiveSelectionRanked, "CompetitiveSelectionRanked",
2345 "len" => len,
2346 "limit" => limit,
2347 "max_score" => max_score,
2348);
2349impl_observational_debug!(ConvergenceGovernor, "ConvergenceGovernor",
2350 "threshold" => threshold,
2351 "awaken_threshold" => awaken_threshold,
2352 "window" => window,
2353 "max_delta" => max_delta,
2354 "state" => state,
2355 "phase" => phase,
2356 "peak_observed" => peak_observed,
2357 "history_len" => history_len,
2358);
2359
2360impl_public_error!(BudgetError, {
2361 Self::AmountExceedsReservation => "amount exceeds the held reservation",
2362 Self::AmountExceedsAllocation => "amount exceeds the committed allocation",
2363 Self::AmountExceedsPendingEviction => "amount exceeds pending eviction",
2364});
2365impl_public_error!(CursorError, {
2366 Self::Regression => "cursor movement would regress the retained position",
2367});
2368impl_public_error!(PropagationBuildError, {
2369 Self::InitialValueOutOfRange => "an initial value exceeds the declared value ceiling",
2370 Self::EdgeEndpointOutOfRange => "an edge endpoint is outside the admitted node set",
2371});
2372impl_public_error!(PropagationError, {
2373 Self::NodeOutOfRange => "node is outside the admitted graph",
2374 Self::RoundAlreadyRunning => "a propagation round is already running",
2375 Self::RoundNotRunning => "no propagation round is running",
2376 Self::NodeAlreadyUpdated => "node already committed an update in this round",
2377 Self::RoundIncomplete => "not every node committed an update",
2378 Self::PassTerminated => "propagation pass is settled or exhausted",
2379 Self::PassStillRunning => "propagation pass has not reached a terminal state",
2380});
2381impl_public_error!(ActuationError, {
2382 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2383 Self::PassComplete => "actuation pass is already complete",
2384 Self::SeatAlreadyAllocated => "seat already holds a resource",
2385 Self::SeatUnallocated => "seat holds no resource",
2386 Self::SeatAlreadyActuated => "seat already committed its effect",
2387 Self::PassIncomplete => "an allocated seat has not committed its effect",
2388});
2389impl_public_error!(QualityHierarchyError, {
2390 Self::NodeOutOfRange => "node is outside the admitted hierarchy",
2391 Self::ParentOutOfRange => "parent is outside the admitted hierarchy",
2392 Self::ChildOutOfRange => "child is outside the admitted hierarchy",
2393 Self::LevelOutOfRange => "level exceeds the hierarchy ceiling",
2394 Self::CostOutOfRange => "cost exceeds the hierarchy ceiling",
2395 Self::NodeNotIsolated => "node properties may change only while the node is isolated",
2396 Self::SelfEdge => "a hierarchy node cannot be its own child",
2397 Self::EdgeAlreadyExists => "the parent-child edge already exists",
2398 Self::ChildAlreadyParented => "the child already has a parent",
2399 Self::LevelOrderViolation => "parent level must strictly exceed child level",
2400 Self::CostOrderViolation => "parent cost must not exceed child cost",
2401});
2402impl_public_error!(BacktrackingBuildError, {
2403 Self::InitialAuxOutOfRange => "initial auxiliary value is outside the modulo-three domain",
2404});
2405impl_public_error!(BacktrackingError, {
2406 Self::AtLeaf => "descent is disabled at a leaf",
2407 Self::ChoiceOutOfRange => "branch choice is outside the admitted branch set",
2408 Self::DeltaOutOfRange => "mutation delta must be one or two",
2409 Self::NotLeaf => "visit requires a full-depth leaf",
2410 Self::AlreadyVisited => "the current leaf was already visited",
2411 Self::AtRoot => "ascent is disabled at the root",
2412});
2413impl_public_error!(CompetitiveSelectionError, {
2414 Self::NoCandidates => "at least one candidate is required",
2415 Self::CandidateOutOfRange => "candidate is outside the admitted candidate set",
2416 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2417 Self::SeatAlreadyAllocated => "seat already holds an allocation",
2418 Self::NoCandidateAvailable => "no candidate is available for the seat",
2419 Self::ScoreOutOfRange => "score is outside the admitted score domain",
2420 Self::ScoreCountMismatch => "replacement scores have a different candidate count",
2421 Self::WeightTotalBelowReservedFloor => "weight total is smaller than the reserved candidate floor",
2422 Self::WeightTotalOutOfRange => "weight total exceeds the verified arithmetic ceiling",
2423 Self::MaxScoreOutOfRange => "maximum score exceeds the verified arithmetic ceiling",
2424 Self::AllocationComplete => "all soft-selection weight has been assigned",
2425});
2426impl_public_error!(ConvergenceBuildError, {
2427 Self::ThresholdOutOfRange => "convergence threshold cannot be doubled safely",
2428 Self::EmptyWindow => "convergence history window must be nonempty",
2429 Self::WindowSumOutOfRange => "maximum convergence window sum exceeds u64",
2430});
2431impl_public_error!(ConvergenceError, {
2432 Self::DeltaOutOfRange => "delta exceeds the configured maximum",
2433});