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 {
310 inner: AuditSinkCarrier,
311}
312
313impl AuditSink {
314 #[verifier::type_invariant]
315 closed spec fn well_formed(&self) -> bool {
316 self.inner.inv()
317 }
318
319 pub fn new(capacity: usize) -> (sink: Self) {
321 let inner = AuditSinkCarrier::new(capacity);
322 Self { inner }
323 }
324
325 pub fn capacity(&self) -> usize {
327 self.inner.max_log_len
328 }
329
330 pub fn len(&self) -> usize {
332 self.inner.log.len()
333 }
334
335 pub fn is_empty(&self) -> bool {
337 self.inner.log.is_empty()
338 }
339
340 pub fn last_hash(&self) -> u64 {
342 self.inner.last_hash
343 }
344
345 #[must_use]
347 pub fn try_record(&mut self, operation: u64) -> (accepted: bool) {
348 proof { use_type_invariant(&*self); }
349 let mut carrier = audit_sentinel();
350 core::mem::swap(&mut self.inner, &mut carrier);
351 let accepted = carrier.record(operation);
352 core::mem::swap(&mut self.inner, &mut carrier);
353 accepted
354 }
355
356 pub fn validate(&self) -> (valid: bool) {
358 proof { use_type_invariant(&*self); }
359 self.inner.validate()
360 }
361
362 #[expect(clippy::indexing_slicing, reason = "the branch proves the audit index is in bounds")]
364 pub fn record(&self, index: usize) -> Option<AuditRecord> {
365 if index < self.inner.log.len() {
366 let entry = &self.inner.log[index];
367 Some(AuditRecord {
368 operation: entry.operation,
369 previous_hash: entry.prev_hash,
370 hash: entry.hash,
371 })
372 } else {
373 None
374 }
375 }
376}
377
378#[derive(Clone, Copy, Debug, Eq, PartialEq)]
380#[non_exhaustive]
381pub enum CursorError {
382 Regression,
384}
385
386pub struct Cursor {
399 inner: CursorCarrier,
400}
401
402impl Cursor {
403 pub fn new(position: usize) -> (cursor: Self) {
405 Self { inner: CursorCarrier::new(position) }
406 }
407
408 pub fn position(&self) -> usize {
410 self.inner.position
411 }
412
413 pub fn advance_to(&mut self, position: usize) -> (result: Result<(), CursorError>) {
419 if position < self.inner.position {
420 return Err(CursorError::Regression);
421 }
422 self.inner.advance_to(position);
423 Ok(())
424 }
425}
426
427#[derive(Clone, Copy, Debug, Eq, PartialEq)]
429#[non_exhaustive]
430pub enum PropagationBuildError {
431 InitialValueOutOfRange,
433 EdgeEndpointOutOfRange,
435}
436
437#[derive(Clone, Copy, Debug, Eq, PartialEq)]
439#[non_exhaustive]
440pub enum PropagationError {
441 NodeOutOfRange,
443 RoundAlreadyRunning,
445 RoundNotRunning,
447 NodeAlreadyUpdated,
449 RoundIncomplete,
451 PassTerminated,
453 PassStillRunning,
455}
456
457pub struct PropagationPass {
473 inner: PropagationPassCarrier,
474}
475
476impl PropagationPass {
477 #[verifier::type_invariant]
478 closed spec fn well_formed(&self) -> bool {
479 self.inner.inv()
480 }
481
482 pub fn new(
488 max_iterations: u64,
489 max_value: u64,
490 edges: Vec<(usize, usize)>,
491 initial_values: Vec<u64>,
492 ) -> (result: Result<Self, PropagationBuildError>) {
493 if !values_within_max(&initial_values, max_value) {
494 return Err(PropagationBuildError::InitialValueOutOfRange);
495 }
496 let num_nodes = initial_values.len();
497 if !edges_within_nodes(&edges, num_nodes) {
498 return Err(PropagationBuildError::EdgeEndpointOutOfRange);
499 }
500 let inner = PropagationPassCarrier::new(
501 num_nodes,
502 max_iterations,
503 max_value,
504 edges,
505 initial_values,
506 );
507 Ok(Self { inner })
508 }
509
510 pub fn num_nodes(&self) -> usize {
512 self.inner.num_nodes
513 }
514
515 pub fn max_iterations(&self) -> u64 {
517 self.inner.max_iterations
518 }
519
520 pub fn max_value(&self) -> u64 {
522 self.inner.max_value
523 }
524
525 pub fn iteration(&self) -> u64 {
527 self.inner.iteration
528 }
529
530 pub fn round(&self) -> PropagationRound {
532 self.inner.round
533 }
534
535 pub fn changed(&self) -> bool {
537 self.inner.changed
538 }
539
540 #[expect(clippy::indexing_slicing, reason = "the branch proves the node index is in bounds")]
542 pub fn value(&self, node: usize) -> Option<u64> {
543 if node < self.inner.values.len() {
544 Some(self.inner.values[node])
545 } else {
546 None
547 }
548 }
549
550 #[expect(clippy::indexing_slicing, reason = "the branch proves the snapshot index is in bounds")]
552 pub fn snapshot_value(&self, node: usize) -> Option<u64> {
553 if node < self.inner.snapshot.len() {
554 Some(self.inner.snapshot[node])
555 } else {
556 None
557 }
558 }
559
560 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
562 pub fn node_updated(&self, node: usize) -> Option<bool> {
563 if node < self.inner.updated.len() {
564 Some(self.inner.updated[node])
565 } else {
566 None
567 }
568 }
569
570 pub fn start_round(&mut self) -> (result: Result<(), PropagationError>) {
576 proof { use_type_invariant(&*self); }
577 match self.inner.round {
578 PropagationRound::Running => {
579 return Err(PropagationError::RoundAlreadyRunning);
580 },
581 PropagationRound::Idle => {},
582 }
583 if !self.inner.changed || self.inner.iteration >= self.inner.max_iterations {
584 return Err(PropagationError::PassTerminated);
585 }
586 let mut carrier = propagation_sentinel();
587 core::mem::swap(&mut self.inner, &mut carrier);
588 carrier.start_round();
589 core::mem::swap(&mut self.inner, &mut carrier);
590 Ok(())
591 }
592
593 #[expect(clippy::indexing_slicing, reason = "the branch proves the update index is in bounds")]
599 pub fn update_node(&mut self, node: usize) -> (result: Result<(), PropagationError>) {
600 proof { use_type_invariant(&*self); }
601 match self.inner.round {
602 PropagationRound::Idle => {
603 return Err(PropagationError::RoundNotRunning);
604 },
605 PropagationRound::Running => {},
606 }
607 if node >= self.inner.num_nodes {
608 return Err(PropagationError::NodeOutOfRange);
609 }
610 if self.inner.updated[node] {
611 return Err(PropagationError::NodeAlreadyUpdated);
612 }
613 let mut carrier = propagation_sentinel();
614 core::mem::swap(&mut self.inner, &mut carrier);
615 carrier.update_node(node);
616 core::mem::swap(&mut self.inner, &mut carrier);
617 Ok(())
618 }
619
620 pub fn end_round(&mut self) -> (result: Result<(), PropagationError>) {
626 proof { use_type_invariant(&*self); }
627 match self.inner.round {
628 PropagationRound::Idle => {
629 return Err(PropagationError::RoundNotRunning);
630 },
631 PropagationRound::Running => {},
632 }
633 if !self.inner.all_nodes_updated() {
634 return Err(PropagationError::RoundIncomplete);
635 }
636 let mut carrier = propagation_sentinel();
637 core::mem::swap(&mut self.inner, &mut carrier);
638 carrier.end_round();
639 core::mem::swap(&mut self.inner, &mut carrier);
640 Ok(())
641 }
642
643 pub fn terminate(&mut self) -> (result: Result<(), PropagationError>) {
649 proof { use_type_invariant(&*self); }
650 match self.inner.round {
651 PropagationRound::Running => {
652 return Err(PropagationError::RoundAlreadyRunning);
653 },
654 PropagationRound::Idle => {},
655 }
656 if self.inner.changed && self.inner.iteration != self.inner.max_iterations {
657 return Err(PropagationError::PassStillRunning);
658 }
659 let mut carrier = propagation_sentinel();
660 core::mem::swap(&mut self.inner, &mut carrier);
661 carrier.terminate();
662 core::mem::swap(&mut self.inner, &mut carrier);
663 Ok(())
664 }
665}
666
667#[derive(Clone, Copy, Debug, Eq, PartialEq)]
669#[non_exhaustive]
670pub enum ActuationError {
671 SeatOutOfRange,
673 PassComplete,
675 SeatAlreadyAllocated,
677 SeatUnallocated,
679 SeatAlreadyActuated,
681 PassIncomplete,
683}
684
685pub struct ActuationPass {
699 inner: ActuationPassCarrier,
700}
701
702impl ActuationPass {
703 #[verifier::type_invariant]
704 closed spec fn well_formed(&self) -> bool {
705 self.inner.invariant()
706 }
707
708 pub fn new(allocation: Vec<Option<u64>>) -> (pass: Self) {
710 let num_seats = allocation.len();
711 let inner = ActuationPassCarrier::new(allocation, num_seats);
712 Self { inner }
713 }
714
715 pub fn len(&self) -> usize {
717 self.inner.num_seats
718 }
719
720 pub fn is_empty(&self) -> bool {
722 self.inner.num_seats == 0
723 }
724
725 pub fn is_complete(&self) -> bool {
727 self.inner.complete
728 }
729
730 #[expect(clippy::indexing_slicing, reason = "the branch proves the allocation index is in bounds")]
732 pub fn allocation(&self, seat: usize) -> Option<Option<u64>> {
733 if seat < self.inner.allocation.len() {
734 Some(self.inner.allocation[seat])
735 } else {
736 None
737 }
738 }
739
740 #[expect(clippy::indexing_slicing, reason = "the branch proves the effect index is in bounds")]
742 pub fn effect(&self, seat: usize) -> Option<Option<u64>> {
743 if seat < self.inner.effects.len() {
744 Some(self.inner.effects[seat])
745 } else {
746 None
747 }
748 }
749
750 pub fn allocate(&mut self, seat: usize, resource: u64) -> (result: Result<(), ActuationError>) {
756 proof { use_type_invariant(&*self); }
757 if seat >= self.inner.num_seats {
758 return Err(ActuationError::SeatOutOfRange);
759 }
760 if self.inner.complete {
761 return Err(ActuationError::PassComplete);
762 }
763 if !self.inner.can_allocate(seat) {
764 return Err(ActuationError::SeatAlreadyAllocated);
765 }
766 let mut carrier = actuation_sentinel();
767 core::mem::swap(&mut self.inner, &mut carrier);
768 carrier.allocate(seat, resource);
769 core::mem::swap(&mut self.inner, &mut carrier);
770 Ok(())
771 }
772
773 pub fn deallocate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
779 proof { use_type_invariant(&*self); }
780 if seat >= self.inner.num_seats {
781 return Err(ActuationError::SeatOutOfRange);
782 }
783 if self.inner.complete {
784 return Err(ActuationError::PassComplete);
785 }
786 if !self.inner.is_allocated(seat) {
787 return Err(ActuationError::SeatUnallocated);
788 }
789 if !self.inner.can_deallocate(seat) {
790 return Err(ActuationError::SeatAlreadyActuated);
791 }
792 let mut carrier = actuation_sentinel();
793 core::mem::swap(&mut self.inner, &mut carrier);
794 carrier.deallocate(seat);
795 core::mem::swap(&mut self.inner, &mut carrier);
796 Ok(())
797 }
798
799 pub fn actuate(&mut self, seat: usize) -> (result: Result<(), ActuationError>) {
805 proof { use_type_invariant(&*self); }
806 if seat >= self.inner.num_seats {
807 return Err(ActuationError::SeatOutOfRange);
808 }
809 if self.inner.complete {
810 return Err(ActuationError::PassComplete);
811 }
812 if !self.inner.is_allocated(seat) {
813 return Err(ActuationError::SeatUnallocated);
814 }
815 if !self.inner.can_actuate(seat) {
816 return Err(ActuationError::SeatAlreadyActuated);
817 }
818 let mut carrier = actuation_sentinel();
819 core::mem::swap(&mut self.inner, &mut carrier);
820 carrier.actuate(seat);
821 core::mem::swap(&mut self.inner, &mut carrier);
822 Ok(())
823 }
824
825 pub fn ready_to_finish(&self) -> (ready: bool) {
827 proof { use_type_invariant(&*self); }
828 self.inner.ready_to_finish_exec()
829 }
830
831 pub fn finish(&mut self) -> (result: Result<(), ActuationError>) {
837 proof { use_type_invariant(&*self); }
838 if self.inner.complete {
839 return Err(ActuationError::PassComplete);
840 }
841 if !self.inner.ready_to_finish_exec() {
842 return Err(ActuationError::PassIncomplete);
843 }
844 let mut carrier = actuation_sentinel();
845 core::mem::swap(&mut self.inner, &mut carrier);
846 carrier.finish();
847 core::mem::swap(&mut self.inner, &mut carrier);
848 Ok(())
849 }
850}
851
852#[derive(Clone, Copy, Debug, Eq, PartialEq)]
854#[non_exhaustive]
855pub enum QualityHierarchyError {
856 NodeOutOfRange,
858 ParentOutOfRange,
860 ChildOutOfRange,
862 LevelOutOfRange,
864 CostOutOfRange,
866 NodeNotIsolated,
868 SelfEdge,
870 EdgeAlreadyExists,
872 ChildAlreadyParented,
874 LevelOrderViolation,
876 CostOrderViolation,
878}
879
880pub struct QualityHierarchy {
895 inner: QualityHierarchyCarrier,
896}
897
898impl QualityHierarchy {
899 #[verifier::type_invariant]
900 closed spec fn well_formed(&self) -> bool {
901 self.inner.type_invariant()
902 && self.inner.strict_level_descent()
903 && self.inner.parent_edge_agreement()
904 && self.inner.cost_monotonicity()
905 }
906
907 pub fn new(num_nodes: usize, max_level: u64) -> (hierarchy: Self) {
909 let inner = QualityHierarchyCarrier::new(num_nodes, max_level);
910 Self { inner }
911 }
912
913 pub fn len(&self) -> usize {
915 self.inner.num_nodes
916 }
917
918 pub fn is_empty(&self) -> bool {
920 self.inner.num_nodes == 0
921 }
922
923 pub fn max_level(&self) -> u64 {
925 self.inner.max_level
926 }
927
928 pub fn level(&self, node: usize) -> Option<u64> {
930 proof { use_type_invariant(&*self); }
931 if node < self.inner.num_nodes {
932 Some(self.inner.level_of(node))
933 } else {
934 None
935 }
936 }
937
938 pub fn cost(&self, node: usize) -> Option<u64> {
940 proof { use_type_invariant(&*self); }
941 if node < self.inner.num_nodes {
942 Some(self.inner.cost_of(node))
943 } else {
944 None
945 }
946 }
947
948 pub fn parent(&self, node: usize) -> Option<usize> {
950 proof { use_type_invariant(&*self); }
951 if node >= self.inner.num_nodes {
952 return None;
953 }
954 let parent = self.inner.parent_of(node);
955 if parent == self.inner.num_nodes {
956 None
957 } else {
958 Some(parent)
959 }
960 }
961
962 pub fn edge_count(&self) -> usize {
964 self.inner.edges.len()
965 }
966
967 #[expect(clippy::indexing_slicing, reason = "the branch proves the hierarchy edge index is in bounds")]
969 pub fn edge(&self, index: usize) -> Option<(usize, usize)> {
970 if index < self.inner.edges.len() {
971 Some(self.inner.edges[index])
972 } else {
973 None
974 }
975 }
976
977 pub fn set_node_properties(
983 &mut self,
984 node: usize,
985 level: u64,
986 cost: u64,
987 ) -> (result: Result<(), QualityHierarchyError>) {
988 proof { use_type_invariant(&*self); }
989 if node >= self.inner.num_nodes {
990 return Err(QualityHierarchyError::NodeOutOfRange);
991 }
992 if level > self.inner.max_level {
993 return Err(QualityHierarchyError::LevelOutOfRange);
994 }
995 if cost > self.inner.max_level {
996 return Err(QualityHierarchyError::CostOutOfRange);
997 }
998 if !self.inner.can_set_node_properties(node, level, cost) {
999 return Err(QualityHierarchyError::NodeNotIsolated);
1000 }
1001 let mut carrier = quality_hierarchy_sentinel();
1002 core::mem::swap(&mut self.inner, &mut carrier);
1003 carrier.set_node_properties(node, level, cost);
1004 core::mem::swap(&mut self.inner, &mut carrier);
1005 Ok(())
1006 }
1007
1008 pub fn add_child(
1014 &mut self,
1015 parent: usize,
1016 child: usize,
1017 ) -> (result: Result<(), QualityHierarchyError>) {
1018 proof { use_type_invariant(&*self); }
1019 if parent >= self.inner.num_nodes {
1020 return Err(QualityHierarchyError::ParentOutOfRange);
1021 }
1022 if child >= self.inner.num_nodes {
1023 return Err(QualityHierarchyError::ChildOutOfRange);
1024 }
1025 if self.inner.can_add_child(parent, child) {
1026 let mut carrier = quality_hierarchy_sentinel();
1027 core::mem::swap(&mut self.inner, &mut carrier);
1028 carrier.add_child(parent, child);
1029 core::mem::swap(&mut self.inner, &mut carrier);
1030 return Ok(());
1031 }
1032 if parent == child {
1033 Err(QualityHierarchyError::SelfEdge)
1034 } else if self.inner.has_edge(parent, child) {
1035 Err(QualityHierarchyError::EdgeAlreadyExists)
1036 } else if self.inner.parent_of(child) != self.inner.num_nodes {
1037 Err(QualityHierarchyError::ChildAlreadyParented)
1038 } else if self.inner.level_of(parent) <= self.inner.level_of(child) {
1039 Err(QualityHierarchyError::LevelOrderViolation)
1040 } else {
1041 Err(QualityHierarchyError::CostOrderViolation)
1042 }
1043 }
1044}
1045
1046#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1048#[non_exhaustive]
1049pub enum BacktrackingBuildError {
1050 InitialAuxOutOfRange,
1052}
1053
1054#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1056#[non_exhaustive]
1057pub enum BacktrackingError {
1058 AtLeaf,
1060 ChoiceOutOfRange,
1062 DeltaOutOfRange,
1064 NotLeaf,
1066 AlreadyVisited,
1068 AtRoot,
1070}
1071
1072pub struct BacktrackingTraversal {
1087 inner: BacktrackingTraversalCarrier,
1088}
1089
1090impl BacktrackingTraversal {
1091 #[verifier::type_invariant]
1092 closed spec fn well_formed(&self) -> bool {
1093 self.inner.inv()
1094 }
1095
1096 pub fn new(
1102 branch_factor: u64,
1103 max_depth: usize,
1104 initial_aux: u64,
1105 ) -> (result: Result<Self, BacktrackingBuildError>) {
1106 if initial_aux >= 3 {
1107 return Err(BacktrackingBuildError::InitialAuxOutOfRange);
1108 }
1109 let inner = BacktrackingTraversalCarrier::new(branch_factor, max_depth, initial_aux);
1110 Ok(Self { inner })
1111 }
1112
1113 pub fn max_depth(&self) -> usize {
1115 self.inner.max_depth
1116 }
1117
1118 pub fn depth(&self) -> usize {
1120 self.inner.path.len()
1121 }
1122
1123 pub fn auxiliary(&self) -> u64 {
1125 self.inner.aux
1126 }
1127
1128 pub fn visited_count(&self) -> usize {
1130 self.inner.visited.len()
1131 }
1132
1133 pub fn is_leaf(&self) -> bool {
1135 self.inner.is_leaf_exec()
1136 }
1137
1138 #[expect(clippy::indexing_slicing, reason = "the branch proves the path index is in bounds")]
1140 pub fn choice(&self, depth: usize) -> Option<u64> {
1141 if depth < self.inner.path.len() {
1142 Some(self.inner.path[depth])
1143 } else {
1144 None
1145 }
1146 }
1147
1148 pub fn descend(&mut self, choice: u64, delta: u64) -> (result: Result<(), BacktrackingError>) {
1154 proof { use_type_invariant(&*self); }
1155 if self.inner.is_leaf_exec() {
1156 return Err(BacktrackingError::AtLeaf);
1157 }
1158 if choice < 1 || choice > self.inner.branch_factor {
1159 return Err(BacktrackingError::ChoiceOutOfRange);
1160 }
1161 if delta < 1 || delta > 2 {
1162 return Err(BacktrackingError::DeltaOutOfRange);
1163 }
1164 let mut carrier = backtracking_sentinel();
1165 core::mem::swap(&mut self.inner, &mut carrier);
1166 carrier.descend(choice, delta);
1167 core::mem::swap(&mut self.inner, &mut carrier);
1168 Ok(())
1169 }
1170
1171 pub fn visit(&mut self) -> (result: Result<(), BacktrackingError>) {
1177 proof { use_type_invariant(&*self); }
1178 if !self.inner.is_leaf_exec() {
1179 return Err(BacktrackingError::NotLeaf);
1180 }
1181 if !self.inner.can_visit() {
1182 return Err(BacktrackingError::AlreadyVisited);
1183 }
1184 let mut carrier = backtracking_sentinel();
1185 core::mem::swap(&mut self.inner, &mut carrier);
1186 carrier.visit();
1187 core::mem::swap(&mut self.inner, &mut carrier);
1188 Ok(())
1189 }
1190
1191 pub fn ascend(&mut self) -> (result: Result<(), BacktrackingError>) {
1197 proof { use_type_invariant(&*self); }
1198 if !self.inner.can_ascend() {
1199 return Err(BacktrackingError::AtRoot);
1200 }
1201 let mut carrier = backtracking_sentinel();
1202 core::mem::swap(&mut self.inner, &mut carrier);
1203 carrier.ascend();
1204 core::mem::swap(&mut self.inner, &mut carrier);
1205 Ok(())
1206 }
1207}
1208
1209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1211#[non_exhaustive]
1212pub enum CompetitiveSelectionError {
1213 NoCandidates,
1215 CandidateOutOfRange,
1217 SeatOutOfRange,
1219 SeatAlreadyAllocated,
1221 NoCandidateAvailable,
1223 ScoreOutOfRange,
1225 ScoreCountMismatch,
1227 WeightTotalBelowReservedFloor,
1229 WeightTotalOutOfRange,
1231 MaxScoreOutOfRange,
1233 AllocationComplete,
1235}
1236
1237pub struct CompetitiveSelectionHard {
1251 inner: CompetitiveSelectionHardCarrier,
1252}
1253
1254impl CompetitiveSelectionHard {
1255 #[verifier::type_invariant]
1256 closed spec fn well_formed(&self) -> bool {
1257 self.inner.inv() && self.inner.scores.len() >= 1
1258 }
1259
1260 pub fn new(num_candidates: usize) -> (result: Result<Self, CompetitiveSelectionError>) {
1266 if num_candidates == 0 {
1267 return Err(CompetitiveSelectionError::NoCandidates);
1268 }
1269 let inner = CompetitiveSelectionHardCarrier::new(num_candidates);
1270 Ok(Self { inner })
1271 }
1272
1273 pub fn len(&self) -> usize {
1275 self.inner.scores.len()
1276 }
1277
1278 pub fn is_empty(&self) -> bool {
1280 false
1281 }
1282
1283 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1285 pub fn score(&self, candidate: usize) -> Option<u64> {
1286 if candidate < self.inner.scores.len() {
1287 Some(self.inner.scores[candidate])
1288 } else {
1289 None
1290 }
1291 }
1292
1293 pub fn winner(&self) -> Option<usize> {
1295 self.inner.allocation
1296 }
1297
1298 pub fn update_score(
1304 &mut self,
1305 candidate: usize,
1306 score: u64,
1307 ) -> (result: Result<(), CompetitiveSelectionError>) {
1308 proof { use_type_invariant(&*self); }
1309 if candidate >= self.inner.scores.len() {
1310 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1311 }
1312 let mut carrier = hard_selection_sentinel();
1313 core::mem::swap(&mut self.inner, &mut carrier);
1314 carrier.update_score(candidate, score);
1315 core::mem::swap(&mut self.inner, &mut carrier);
1316 Ok(())
1317 }
1318
1319 #[expect(clippy::manual_unwrap_or_default, reason = "the explicit match is supported by the Verus boundary")]
1321 pub fn evaluate(&mut self) -> (winner: usize) {
1322 proof { use_type_invariant(&*self); }
1323 let mut carrier = hard_selection_sentinel();
1324 core::mem::swap(&mut self.inner, &mut carrier);
1325 carrier.evaluate();
1326 let winner = match carrier.allocation {
1327 Some(value) => value,
1328 None => 0,
1329 };
1330 core::mem::swap(&mut self.inner, &mut carrier);
1331 winner
1332 }
1333}
1334
1335pub struct CompetitiveSelectionHardExclusive {
1350 inner: CompetitiveSelectionHardExclusiveCarrier,
1351}
1352
1353impl CompetitiveSelectionHardExclusive {
1354 #[verifier::type_invariant]
1355 closed spec fn well_formed(&self) -> bool {
1356 self.inner.inv()
1357 }
1358
1359 pub fn new(
1365 num_seats: usize,
1366 num_candidates: usize,
1367 max_score: u64,
1368 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1369 if num_candidates == 0 {
1370 return Err(CompetitiveSelectionError::NoCandidates);
1371 }
1372 let inner = CompetitiveSelectionHardExclusiveCarrier::new(
1373 num_seats,
1374 num_candidates,
1375 max_score,
1376 );
1377 Ok(Self { inner })
1378 }
1379
1380 pub fn seat_count(&self) -> usize {
1382 self.inner.num_seats
1383 }
1384
1385 pub fn candidate_count(&self) -> usize {
1387 self.inner.num_candidates
1388 }
1389
1390 pub fn max_score(&self) -> u64 {
1392 self.inner.max_score
1393 }
1394
1395 #[expect(clippy::indexing_slicing, reason = "the branch proves the seat index is in bounds")]
1397 #[expect(clippy::manual_map, reason = "the explicit match is supported by the Verus boundary")]
1398 pub fn allocation(&self, seat: usize) -> Option<usize> {
1399 proof { use_type_invariant(&*self); }
1400 if seat >= self.inner.num_seats {
1401 return None;
1402 }
1403 match self.inner.allocation[seat] {
1404 Some(candidate) => Some(candidate as usize),
1405 None => None,
1406 }
1407 }
1408
1409 #[expect(clippy::indexing_slicing, reason = "the branches prove both score indices are in bounds")]
1411 pub fn score(&self, seat: usize, candidate: usize) -> Option<u64> {
1412 proof { use_type_invariant(&*self); }
1413 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1414 None
1415 } else {
1416 Some(self.inner.scores[seat][candidate])
1417 }
1418 }
1419
1420 pub fn candidate_available(&self, seat: usize, candidate: usize) -> Option<bool> {
1422 proof { use_type_invariant(&*self); }
1423 if seat >= self.inner.num_seats || candidate >= self.inner.num_candidates {
1424 return None;
1425 }
1426 Some(self.inner.candidate_available(seat, candidate))
1427 }
1428
1429 pub fn update_score(
1435 &mut self,
1436 seat: usize,
1437 candidate: usize,
1438 score: u64,
1439 ) -> (result: Result<(), CompetitiveSelectionError>) {
1440 proof { use_type_invariant(&*self); }
1441 if seat >= self.inner.num_seats {
1442 return Err(CompetitiveSelectionError::SeatOutOfRange);
1443 }
1444 if candidate >= self.inner.num_candidates {
1445 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1446 }
1447 if score > self.inner.max_score {
1448 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1449 }
1450 let mut carrier = hard_exclusive_selection_sentinel();
1451 core::mem::swap(&mut self.inner, &mut carrier);
1452 carrier.update_score(seat, candidate, score);
1453 core::mem::swap(&mut self.inner, &mut carrier);
1454 Ok(())
1455 }
1456
1457 #[expect(clippy::indexing_slicing, reason = "the guards prove the seat index is in bounds")]
1463 pub fn evaluate(
1464 &mut self,
1465 seat: usize,
1466 ) -> (result: Result<usize, CompetitiveSelectionError>) {
1467 proof { use_type_invariant(&*self); }
1468 if seat >= self.inner.num_seats {
1469 return Err(CompetitiveSelectionError::SeatOutOfRange);
1470 }
1471 if self.inner.allocation[seat].is_some() {
1472 return Err(CompetitiveSelectionError::SeatAlreadyAllocated);
1473 }
1474 if !self.inner.has_available(seat) {
1475 return Err(CompetitiveSelectionError::NoCandidateAvailable);
1476 }
1477 let mut carrier = hard_exclusive_selection_sentinel();
1478 core::mem::swap(&mut self.inner, &mut carrier);
1479 carrier.evaluate(seat);
1480 let winner = match carrier.allocation[seat] {
1481 Some(candidate) => candidate as usize,
1482 None => 0,
1483 };
1484 core::mem::swap(&mut self.inner, &mut carrier);
1485 Ok(winner)
1486 }
1487}
1488
1489pub struct CompetitiveSelectionSoft {
1501 inner: CompetitiveSelectionSoftCarrier,
1502}
1503
1504impl CompetitiveSelectionSoft {
1505 #[verifier::type_invariant]
1506 closed spec fn well_formed(&self) -> bool {
1507 self.inner.mutable_score_inv()
1508 }
1509
1510 pub fn new(
1516 scores: Vec<u64>,
1517 weight_total: u64,
1518 max_score: u64,
1519 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1520 if scores.is_empty() {
1521 return Err(CompetitiveSelectionError::NoCandidates);
1522 }
1523 if weight_total > 1_000_000_000 {
1524 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1525 }
1526 if max_score > 1_000_000_000 {
1527 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1528 }
1529 if weight_total < scores.len() as u64 {
1530 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1531 }
1532 if !positive_values_within_max(&scores, max_score) {
1533 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1534 }
1535 let inner = CompetitiveSelectionSoftCarrier::new(scores, weight_total, max_score);
1536 Ok(Self { inner })
1537 }
1538
1539 pub fn begin(
1545 scores: Vec<u64>,
1546 weight_total: u64,
1547 max_score: u64,
1548 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1549 if scores.is_empty() {
1550 return Err(CompetitiveSelectionError::NoCandidates);
1551 }
1552 if weight_total > 1_000_000_000 {
1553 return Err(CompetitiveSelectionError::WeightTotalOutOfRange);
1554 }
1555 if max_score > 1_000_000_000 {
1556 return Err(CompetitiveSelectionError::MaxScoreOutOfRange);
1557 }
1558 if weight_total < scores.len() as u64 {
1559 return Err(CompetitiveSelectionError::WeightTotalBelowReservedFloor);
1560 }
1561 if !positive_values_within_max(&scores, max_score) {
1562 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1563 }
1564 let inner = CompetitiveSelectionSoftCarrier::init(scores, weight_total, max_score);
1565 Ok(Self { inner })
1566 }
1567
1568 pub fn len(&self) -> usize {
1570 self.inner.scores.len()
1571 }
1572
1573 pub fn is_empty(&self) -> bool {
1575 false
1576 }
1577
1578 pub fn weight_total(&self) -> u64 {
1580 self.inner.weight_total
1581 }
1582
1583 pub fn max_score(&self) -> u64 {
1585 self.inner.max_score
1586 }
1587
1588 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1590 pub fn score(&self, candidate: usize) -> Option<u64> {
1591 if candidate < self.inner.scores.len() {
1592 Some(self.inner.scores[candidate])
1593 } else {
1594 None
1595 }
1596 }
1597
1598 pub fn weight(&self, candidate: usize) -> Option<u64> {
1600 proof { use_type_invariant(&*self); }
1601 if candidate < self.inner.extra.len() {
1602 Some(self.inner.weight_at(candidate))
1603 } else {
1604 None
1605 }
1606 }
1607
1608 pub fn assigned_weight(&self) -> u64 {
1610 proof { use_type_invariant(&*self); }
1611 self.inner.assigned_weight()
1612 }
1613
1614 pub fn is_complete(&self) -> bool {
1616 self.assigned_weight() == self.inner.weight_total
1617 }
1618
1619 pub fn assign_next(&mut self) -> (result: Result<usize, CompetitiveSelectionError>) {
1625 proof { use_type_invariant(&*self); }
1626 if self.inner.assigned_weight() >= self.inner.weight_total {
1627 return Err(CompetitiveSelectionError::AllocationComplete);
1628 }
1629 let mut carrier = soft_selection_sentinel();
1630 core::mem::swap(&mut self.inner, &mut carrier);
1631 let winner = carrier.assign_next();
1632 core::mem::swap(&mut self.inner, &mut carrier);
1633 Ok(winner)
1634 }
1635
1636 pub fn update_score(
1642 &mut self,
1643 candidate: usize,
1644 score: u64,
1645 ) -> (result: Result<(), CompetitiveSelectionError>) {
1646 proof { use_type_invariant(&*self); }
1647 if candidate >= self.inner.scores.len() {
1648 return Err(CompetitiveSelectionError::CandidateOutOfRange);
1649 }
1650 if score < 1 || score > self.inner.max_score {
1651 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1652 }
1653 let mut carrier = soft_selection_sentinel();
1654 core::mem::swap(&mut self.inner, &mut carrier);
1655 carrier.update_score(candidate, score);
1656 core::mem::swap(&mut self.inner, &mut carrier);
1657 Ok(())
1658 }
1659}
1660
1661pub struct CompetitiveSelectionRanked {
1674 inner: CompetitiveSelectionRankedCarrier,
1675}
1676
1677impl CompetitiveSelectionRanked {
1678 #[verifier::type_invariant]
1679 closed spec fn well_formed(&self) -> bool {
1680 self.inner.inv()
1681 }
1682
1683 pub fn new(
1689 scores: Vec<u64>,
1690 k: usize,
1691 max_score: u64,
1692 ) -> (result: Result<Self, CompetitiveSelectionError>) {
1693 if !values_within_max(&scores, max_score) {
1694 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1695 }
1696 let inner = CompetitiveSelectionRankedCarrier::new(scores, k, max_score);
1697 Ok(Self { inner })
1698 }
1699
1700 pub fn len(&self) -> usize {
1702 self.inner.scores.len()
1703 }
1704
1705 pub fn is_empty(&self) -> bool {
1707 self.inner.scores.is_empty()
1708 }
1709
1710 pub fn limit(&self) -> usize {
1712 self.inner.k
1713 }
1714
1715 pub fn max_score(&self) -> u64 {
1717 self.inner.max_score
1718 }
1719
1720 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1722 pub fn score(&self, candidate: usize) -> Option<u64> {
1723 if candidate < self.inner.scores.len() {
1724 Some(self.inner.scores[candidate])
1725 } else {
1726 None
1727 }
1728 }
1729
1730 #[expect(clippy::indexing_slicing, reason = "the branch proves the candidate index is in bounds")]
1732 pub fn is_selected(&self, candidate: usize) -> Option<bool> {
1733 if candidate < self.inner.selected.len() {
1734 Some(self.inner.selected[candidate])
1735 } else {
1736 None
1737 }
1738 }
1739
1740 pub fn select(&mut self) {
1742 proof { use_type_invariant(&*self); }
1743 let mut carrier = ranked_selection_sentinel();
1744 core::mem::swap(&mut self.inner, &mut carrier);
1745 carrier.select();
1746 core::mem::swap(&mut self.inner, &mut carrier);
1747 }
1748
1749 pub fn update_scores(
1755 &mut self,
1756 scores: Vec<u64>,
1757 ) -> (result: Result<(), CompetitiveSelectionError>) {
1758 proof { use_type_invariant(&*self); }
1759 if scores.len() != self.inner.scores.len() {
1760 return Err(CompetitiveSelectionError::ScoreCountMismatch);
1761 }
1762 if !values_within_max(&scores, self.inner.max_score) {
1763 return Err(CompetitiveSelectionError::ScoreOutOfRange);
1764 }
1765 let mut carrier = ranked_selection_sentinel();
1766 core::mem::swap(&mut self.inner, &mut carrier);
1767 carrier.update_scores(scores);
1768 core::mem::swap(&mut self.inner, &mut carrier);
1769 Ok(())
1770 }
1771}
1772
1773#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1775#[non_exhaustive]
1776pub enum ConvergenceBuildError {
1777 ThresholdOutOfRange,
1779 EmptyWindow,
1781 WindowSumOutOfRange,
1783}
1784
1785#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1787#[non_exhaustive]
1788pub enum ConvergenceError {
1789 DeltaOutOfRange,
1791}
1792
1793pub struct ConvergenceGovernor {
1806 inner: ConvergenceGovernorCarrier,
1807}
1808
1809impl ConvergenceGovernor {
1810 #[verifier::type_invariant]
1811 closed spec fn well_formed(&self) -> bool {
1812 self.inner.inv()
1813 }
1814
1815 pub fn new(
1821 threshold: u64,
1822 awaken_threshold: u64,
1823 window: usize,
1824 max_delta: u64,
1825 ) -> (result: Result<Self, ConvergenceBuildError>) {
1826 if threshold > u64::MAX / 2 {
1827 return Err(ConvergenceBuildError::ThresholdOutOfRange);
1828 }
1829 if window == 0 {
1830 return Err(ConvergenceBuildError::EmptyWindow);
1831 }
1832 if window > 1_000_000_000 || max_delta > 1_000_000_000 {
1833 return Err(ConvergenceBuildError::WindowSumOutOfRange);
1834 }
1835 proof {
1836 assert(window as int * max_delta as int <= u64::MAX as int) by (nonlinear_arith)
1837 requires
1838 window <= 1_000_000_000,
1839 max_delta <= 1_000_000_000,
1840 u64::MAX >= 1_000_000_000 * 1_000_000_000;
1841 }
1842 let inner = ConvergenceGovernorCarrier::new(
1843 threshold,
1844 awaken_threshold,
1845 window,
1846 max_delta,
1847 );
1848 Ok(Self { inner })
1849 }
1850
1851 pub fn threshold(&self) -> u64 {
1853 self.inner.threshold
1854 }
1855
1856 pub fn awaken_threshold(&self) -> u64 {
1858 self.inner.awaken_threshold
1859 }
1860
1861 pub fn window(&self) -> usize {
1863 self.inner.window
1864 }
1865
1866 pub fn max_delta(&self) -> u64 {
1868 self.inner.max_delta
1869 }
1870
1871 pub fn state(&self) -> ConvergenceState {
1873 self.inner.state
1874 }
1875
1876 pub fn phase(&self) -> ConvergencePhase {
1878 self.inner.gradient_phase
1879 }
1880
1881 pub fn peak_observed(&self) -> bool {
1883 self.inner.peak_observed
1884 }
1885
1886 pub fn history_len(&self) -> usize {
1888 self.inner.delta_history.len()
1889 }
1890
1891 #[expect(clippy::indexing_slicing, reason = "the branch proves the history index is in bounds")]
1893 pub fn history(&self, index: usize) -> Option<u64> {
1894 if index < self.inner.delta_history.len() {
1895 Some(self.inner.delta_history[index])
1896 } else {
1897 None
1898 }
1899 }
1900
1901 pub fn update(&mut self, delta: u64) -> (result: Result<u64, ConvergenceError>) {
1907 proof { use_type_invariant(&*self); }
1908 if delta > self.inner.max_delta {
1909 return Err(ConvergenceError::DeltaOutOfRange);
1910 }
1911 let mut carrier = convergence_sentinel();
1912 core::mem::swap(&mut self.inner, &mut carrier);
1913 let average = carrier.update(delta);
1914 core::mem::swap(&mut self.inner, &mut carrier);
1915 Ok(average)
1916 }
1917}
1918
1919fn budget_sentinel() -> (carrier: BudgetCarrier)
1920 ensures carrier.safety_invariant(),
1921{
1922 BudgetCarrier::new(0)
1923}
1924
1925fn registry_sentinel() -> (carrier: RegistryCarrier<u64, u64>)
1926 ensures carrier.unique_mapping(),
1927{
1928 RegistryCarrier::new()
1929}
1930
1931fn audit_sentinel() -> (carrier: AuditSinkCarrier)
1932 ensures carrier.inv(),
1933{
1934 AuditSinkCarrier::new(0)
1935}
1936
1937fn propagation_sentinel() -> (carrier: PropagationPassCarrier)
1938 ensures carrier.inv(),
1939{
1940 let edges: Vec<(usize, usize)> = Vec::new();
1941 let values: Vec<u64> = Vec::new();
1942 PropagationPassCarrier::new(0, 0, 0, edges, values)
1943}
1944
1945fn actuation_sentinel() -> (carrier: ActuationPassCarrier)
1946 ensures carrier.invariant(),
1947{
1948 let allocation: Vec<Option<u64>> = Vec::new();
1949 ActuationPassCarrier::new(allocation, 0)
1950}
1951
1952fn quality_hierarchy_sentinel() -> (carrier: QualityHierarchyCarrier)
1953 ensures
1954 carrier.type_invariant(),
1955 carrier.strict_level_descent(),
1956 carrier.parent_edge_agreement(),
1957 carrier.cost_monotonicity(),
1958{
1959 QualityHierarchyCarrier::new(0, 0)
1960}
1961
1962fn backtracking_sentinel() -> (carrier: BacktrackingTraversalCarrier)
1963 ensures carrier.inv(),
1964{
1965 BacktrackingTraversalCarrier::new(0, 0, 0)
1966}
1967
1968fn hard_selection_sentinel() -> (carrier: CompetitiveSelectionHardCarrier)
1969 ensures
1970 carrier.inv(),
1971 carrier.scores.len() >= 1,
1972{
1973 CompetitiveSelectionHardCarrier::new(1)
1974}
1975
1976fn hard_exclusive_selection_sentinel() -> (carrier: CompetitiveSelectionHardExclusiveCarrier)
1977 ensures carrier.inv(),
1978{
1979 CompetitiveSelectionHardExclusiveCarrier::new(0, 1, 0)
1980}
1981
1982fn soft_selection_sentinel() -> (carrier: CompetitiveSelectionSoftCarrier)
1983 ensures carrier.mutable_score_inv(),
1984{
1985 let mut scores: Vec<u64> = Vec::new();
1986 scores.push(1);
1987 CompetitiveSelectionSoftCarrier::init(scores, 1, 1)
1988}
1989
1990fn ranked_selection_sentinel() -> (carrier: CompetitiveSelectionRankedCarrier)
1991 ensures carrier.inv(),
1992{
1993 let scores: Vec<u64> = Vec::new();
1994 CompetitiveSelectionRankedCarrier::new(scores, 0, 0)
1995}
1996
1997fn convergence_sentinel() -> (carrier: ConvergenceGovernorCarrier)
1998 ensures carrier.inv(),
1999{
2000 ConvergenceGovernorCarrier::new(0, 0, 1, 0)
2001}
2002
2003#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2004#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2005#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2006pub(crate) fn values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2007 ensures
2008 valid == (forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value),
2009{
2010 let mut index: usize = 0;
2011 while index < values.len()
2012 invariant
2013 index <= values.len(),
2014 forall|i: int| 0 <= i < index ==> values@[i] <= max_value,
2015 decreases values.len() - index,
2016 {
2017 if values[index] > max_value {
2018 assert(!(forall|i: int| 0 <= i < values.len() ==> values@[i] <= max_value));
2019 return false;
2020 }
2021 index += 1;
2022 }
2023 true
2024}
2025
2026#[expect(clippy::indexing_slicing, reason = "the loop proves the value index is in bounds")]
2027#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2028#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2029fn positive_values_within_max(values: &Vec<u64>, max_value: u64) -> (valid: bool)
2030 ensures
2031 valid == (forall|i: int| 0 <= i < values.len()
2032 ==> 1 <= #[trigger] values@[i] <= max_value),
2033{
2034 let mut index: usize = 0;
2035 while index < values.len()
2036 invariant
2037 index <= values.len(),
2038 forall|i: int| 0 <= i < index ==> 1 <= #[trigger] values@[i] <= max_value,
2039 decreases values.len() - index,
2040 {
2041 if values[index] < 1 || values[index] > max_value {
2042 assert(!(forall|i: int| 0 <= i < values.len()
2043 ==> 1 <= #[trigger] values@[i] <= max_value));
2044 return false;
2045 }
2046 index += 1;
2047 }
2048 true
2049}
2050
2051#[expect(clippy::indexing_slicing, reason = "the loop proves the edge index is in bounds")]
2052#[expect(clippy::arithmetic_side_effects, reason = "the loop proves the cursor remains within the vector")]
2053#[expect(clippy::ptr_arg, reason = "Verus sequence-view contracts are stated over Vec in this checked boundary")]
2054fn edges_within_nodes(edges: &Vec<(usize, usize)>, num_nodes: usize) -> (valid: bool)
2055 ensures
2056 valid == (forall|i: int| 0 <= i < edges.len()
2057 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes),
2058{
2059 let mut index: usize = 0;
2060 while index < edges.len()
2061 invariant
2062 index <= edges.len(),
2063 forall|i: int| 0 <= i < index
2064 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes,
2065 decreases edges.len() - index,
2066 {
2067 if edges[index].0 >= num_nodes || edges[index].1 >= num_nodes {
2068 assert(!(forall|i: int| 0 <= i < edges.len()
2069 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes));
2070 return false;
2071 }
2072 index += 1;
2073 }
2074 true
2075}
2076
2077} impl Budget {
2080 pub fn is_empty(&self) -> bool {
2082 self.allocated() == 0 && self.reserved() == 0 && self.pending_eviction() == 0
2083 }
2084
2085 pub fn is_full(&self) -> bool {
2087 self.available() == 0
2088 }
2089}
2090
2091impl ResourceRegistry {
2092 pub fn contains_key(&self, key: u64) -> bool {
2094 self.get(key).is_some()
2095 }
2096
2097 pub fn iter(&self) -> impl ExactSizeIterator<Item = &(u64, u64)> {
2099 self.inner.entries.iter()
2100 }
2101}
2102
2103impl AuditSink {
2104 pub fn is_full(&self) -> bool {
2106 self.len() == self.capacity()
2107 }
2108
2109 pub fn records(&self) -> impl ExactSizeIterator<Item = AuditRecord> + '_ {
2111 self.inner.log.iter().map(|entry| AuditRecord {
2112 operation: entry.operation,
2113 previous_hash: entry.prev_hash,
2114 hash: entry.hash,
2115 })
2116 }
2117}
2118
2119impl PropagationPass {
2120 pub fn edges(&self) -> &[(usize, usize)] {
2122 self.inner.edges.as_slice()
2123 }
2124
2125 pub fn values(&self) -> &[u64] {
2127 self.inner.values.as_slice()
2128 }
2129
2130 pub fn snapshot_values(&self) -> &[u64] {
2132 self.inner.snapshot.as_slice()
2133 }
2134
2135 pub fn updated_nodes(&self) -> &[bool] {
2137 self.inner.updated.as_slice()
2138 }
2139}
2140
2141impl ActuationPass {
2142 pub fn allocations(&self) -> &[Option<u64>] {
2144 self.inner.allocation.as_slice()
2145 }
2146
2147 pub fn effects(&self) -> &[Option<u64>] {
2149 self.inner.effects.as_slice()
2150 }
2151}
2152
2153impl QualityHierarchy {
2154 pub fn levels(&self) -> &[u64] {
2156 self.inner.level.as_slice()
2157 }
2158
2159 pub fn costs(&self) -> &[u64] {
2161 self.inner.cost.as_slice()
2162 }
2163
2164 pub fn encoded_parents(&self) -> &[usize] {
2168 self.inner.parent.as_slice()
2169 }
2170
2171 pub fn edges(&self) -> &[(usize, usize)] {
2173 self.inner.edges.as_slice()
2174 }
2175
2176 pub fn has_children(&self, node: usize) -> Option<bool> {
2178 (node < self.len()).then(|| self.inner.has_children(node))
2179 }
2180
2181 pub fn has_edge(&self, parent: usize, child: usize) -> Option<bool> {
2183 (parent < self.len() && child < self.len()).then(|| self.inner.has_edge(parent, child))
2184 }
2185}
2186
2187impl BacktrackingTraversal {
2188 pub fn branch_factor(&self) -> u64 {
2190 self.inner.branch_factor
2191 }
2192
2193 pub fn initial_auxiliary(&self) -> u64 {
2195 self.inner.init_aux
2196 }
2197
2198 pub fn choices(&self) -> &[u64] {
2200 self.inner.path.as_slice()
2201 }
2202
2203 pub fn visited_paths(&self) -> impl ExactSizeIterator<Item = &[u64]> {
2205 self.inner.visited.iter().map(Vec::as_slice)
2206 }
2207}
2208
2209impl CompetitiveSelectionHard {
2210 pub fn scores(&self) -> &[u64] {
2212 self.inner.scores.as_slice()
2213 }
2214}
2215
2216impl CompetitiveSelectionHardExclusive {
2217 pub fn is_empty(&self) -> bool {
2219 self.seat_count() == 0
2220 }
2221
2222 pub fn allocations(&self) -> &[Option<u64>] {
2224 self.inner.allocation.as_slice()
2225 }
2226
2227 pub fn scores(&self, seat: usize) -> Option<&[u64]> {
2229 self.inner.scores.get(seat).map(Vec::as_slice)
2230 }
2231}
2232
2233impl CompetitiveSelectionSoft {
2234 pub fn scores(&self) -> &[u64] {
2236 self.inner.scores.as_slice()
2237 }
2238
2239 pub fn weights(&self) -> impl ExactSizeIterator<Item = u64> + '_ {
2241 self.inner.extra.iter().map(|extra| extra + 1)
2242 }
2243}
2244
2245impl CompetitiveSelectionRanked {
2246 pub fn scores(&self) -> &[u64] {
2248 self.inner.scores.as_slice()
2249 }
2250
2251 pub fn selections(&self) -> &[bool] {
2253 self.inner.selected.as_slice()
2254 }
2255
2256 pub fn selected_len(&self) -> usize {
2258 self.inner
2259 .selected
2260 .iter()
2261 .filter(|selected| **selected)
2262 .count()
2263 }
2264}
2265
2266impl ConvergenceGovernor {
2267 pub fn history_values(&self) -> &[u64] {
2269 self.inner.delta_history.as_slice()
2270 }
2271}
2272
2273impl Default for ResourceRegistry {
2274 fn default() -> Self {
2275 Self::new()
2276 }
2277}
2278
2279impl_observational_debug!(Budget, "Budget",
2280 "capacity" => capacity,
2281 "allocated" => allocated,
2282 "reserved" => reserved,
2283 "pending_eviction" => pending_eviction,
2284 "available" => available,
2285);
2286impl_observational_debug!(ResourceRegistry, "ResourceRegistry", "len" => len);
2287impl_observational_debug!(AuditSink, "AuditSink",
2288 "capacity" => capacity,
2289 "len" => len,
2290 "last_hash" => last_hash,
2291 "valid" => validate,
2292);
2293impl_observational_debug!(Cursor, "Cursor", "position" => position);
2294impl_observational_debug!(PropagationPass, "PropagationPass",
2295 "num_nodes" => num_nodes,
2296 "max_iterations" => max_iterations,
2297 "iteration" => iteration,
2298 "round" => round,
2299 "changed" => changed,
2300);
2301impl_observational_debug!(ActuationPass, "ActuationPass",
2302 "len" => len,
2303 "complete" => is_complete,
2304 "ready_to_finish" => ready_to_finish,
2305);
2306impl_observational_debug!(QualityHierarchy, "QualityHierarchy",
2307 "len" => len,
2308 "max_level" => max_level,
2309 "edge_count" => edge_count,
2310);
2311impl_observational_debug!(BacktrackingTraversal, "BacktrackingTraversal",
2312 "max_depth" => max_depth,
2313 "depth" => depth,
2314 "auxiliary" => auxiliary,
2315 "visited_count" => visited_count,
2316 "leaf" => is_leaf,
2317);
2318impl_observational_debug!(CompetitiveSelectionHard, "CompetitiveSelectionHard",
2319 "len" => len,
2320 "winner" => winner,
2321);
2322impl_observational_debug!(CompetitiveSelectionHardExclusive, "CompetitiveSelectionHardExclusive",
2323 "seat_count" => seat_count,
2324 "candidate_count" => candidate_count,
2325 "max_score" => max_score,
2326);
2327impl_observational_debug!(CompetitiveSelectionSoft, "CompetitiveSelectionSoft",
2328 "len" => len,
2329 "weight_total" => weight_total,
2330 "assigned_weight" => assigned_weight,
2331 "max_score" => max_score,
2332 "complete" => is_complete,
2333);
2334impl_observational_debug!(CompetitiveSelectionRanked, "CompetitiveSelectionRanked",
2335 "len" => len,
2336 "limit" => limit,
2337 "max_score" => max_score,
2338);
2339impl_observational_debug!(ConvergenceGovernor, "ConvergenceGovernor",
2340 "threshold" => threshold,
2341 "awaken_threshold" => awaken_threshold,
2342 "window" => window,
2343 "max_delta" => max_delta,
2344 "state" => state,
2345 "phase" => phase,
2346 "peak_observed" => peak_observed,
2347 "history_len" => history_len,
2348);
2349
2350impl_public_error!(BudgetError, {
2351 Self::AmountExceedsReservation => "amount exceeds the held reservation",
2352 Self::AmountExceedsAllocation => "amount exceeds the committed allocation",
2353 Self::AmountExceedsPendingEviction => "amount exceeds pending eviction",
2354});
2355impl_public_error!(CursorError, {
2356 Self::Regression => "cursor movement would regress the retained position",
2357});
2358impl_public_error!(PropagationBuildError, {
2359 Self::InitialValueOutOfRange => "an initial value exceeds the declared value ceiling",
2360 Self::EdgeEndpointOutOfRange => "an edge endpoint is outside the admitted node set",
2361});
2362impl_public_error!(PropagationError, {
2363 Self::NodeOutOfRange => "node is outside the admitted graph",
2364 Self::RoundAlreadyRunning => "a propagation round is already running",
2365 Self::RoundNotRunning => "no propagation round is running",
2366 Self::NodeAlreadyUpdated => "node already committed an update in this round",
2367 Self::RoundIncomplete => "not every node committed an update",
2368 Self::PassTerminated => "propagation pass is settled or exhausted",
2369 Self::PassStillRunning => "propagation pass has not reached a terminal state",
2370});
2371impl_public_error!(ActuationError, {
2372 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2373 Self::PassComplete => "actuation pass is already complete",
2374 Self::SeatAlreadyAllocated => "seat already holds a resource",
2375 Self::SeatUnallocated => "seat holds no resource",
2376 Self::SeatAlreadyActuated => "seat already committed its effect",
2377 Self::PassIncomplete => "an allocated seat has not committed its effect",
2378});
2379impl_public_error!(QualityHierarchyError, {
2380 Self::NodeOutOfRange => "node is outside the admitted hierarchy",
2381 Self::ParentOutOfRange => "parent is outside the admitted hierarchy",
2382 Self::ChildOutOfRange => "child is outside the admitted hierarchy",
2383 Self::LevelOutOfRange => "level exceeds the hierarchy ceiling",
2384 Self::CostOutOfRange => "cost exceeds the hierarchy ceiling",
2385 Self::NodeNotIsolated => "node properties may change only while the node is isolated",
2386 Self::SelfEdge => "a hierarchy node cannot be its own child",
2387 Self::EdgeAlreadyExists => "the parent-child edge already exists",
2388 Self::ChildAlreadyParented => "the child already has a parent",
2389 Self::LevelOrderViolation => "parent level must strictly exceed child level",
2390 Self::CostOrderViolation => "parent cost must not exceed child cost",
2391});
2392impl_public_error!(BacktrackingBuildError, {
2393 Self::InitialAuxOutOfRange => "initial auxiliary value is outside the modulo-three domain",
2394});
2395impl_public_error!(BacktrackingError, {
2396 Self::AtLeaf => "descent is disabled at a leaf",
2397 Self::ChoiceOutOfRange => "branch choice is outside the admitted branch set",
2398 Self::DeltaOutOfRange => "mutation delta must be one or two",
2399 Self::NotLeaf => "visit requires a full-depth leaf",
2400 Self::AlreadyVisited => "the current leaf was already visited",
2401 Self::AtRoot => "ascent is disabled at the root",
2402});
2403impl_public_error!(CompetitiveSelectionError, {
2404 Self::NoCandidates => "at least one candidate is required",
2405 Self::CandidateOutOfRange => "candidate is outside the admitted candidate set",
2406 Self::SeatOutOfRange => "seat is outside the admitted seat set",
2407 Self::SeatAlreadyAllocated => "seat already holds an allocation",
2408 Self::NoCandidateAvailable => "no candidate is available for the seat",
2409 Self::ScoreOutOfRange => "score is outside the admitted score domain",
2410 Self::ScoreCountMismatch => "replacement scores have a different candidate count",
2411 Self::WeightTotalBelowReservedFloor => "weight total is smaller than the reserved candidate floor",
2412 Self::WeightTotalOutOfRange => "weight total exceeds the verified arithmetic ceiling",
2413 Self::MaxScoreOutOfRange => "maximum score exceeds the verified arithmetic ceiling",
2414 Self::AllocationComplete => "all soft-selection weight has been assigned",
2415});
2416impl_public_error!(ConvergenceBuildError, {
2417 Self::ThresholdOutOfRange => "convergence threshold cannot be doubled safely",
2418 Self::EmptyWindow => "convergence history window must be nonempty",
2419 Self::WindowSumOutOfRange => "maximum convergence window sum exceeds u64",
2420});
2421impl_public_error!(ConvergenceError, {
2422 Self::DeltaOutOfRange => "delta exceeds the configured maximum",
2423});