sim_lib_discrete_comb/
bit_vector.rs1use crate::error::CombError;
7use num_bigint::BigUint;
8
9const MAX_WIDTH: usize = 127;
11
12#[derive(Debug, Clone)]
14pub struct BitVectorIter {
15 width: usize,
16 next: u128,
17 total: u128,
18}
19
20impl BitVectorIter {
21 pub fn total_ordinals(&self) -> u128 {
23 self.total
24 }
25
26 pub fn remaining_ordinals(&self) -> u128 {
28 self.total.saturating_sub(self.next)
29 }
30}
31
32pub fn bit_vectors(width: usize) -> Result<BitVectorIter, CombError> {
35 if width > MAX_WIDTH {
36 return Err(CombError::LimitExceeded(format!(
37 "bit-vector width {width} exceeds {MAX_WIDTH}"
38 )));
39 }
40 let total = 1u128 << width;
41 Ok(BitVectorIter {
42 width,
43 next: 0,
44 total,
45 })
46}
47
48impl Iterator for BitVectorIter {
49 type Item = Vec<bool>;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 if self.next >= self.total {
53 return None;
54 }
55 let r = self.next;
56 self.next += 1;
57 Some((0..self.width).map(|j| (r >> j) & 1 == 1).collect())
58 }
59}
60
61pub fn bit_vector_rank(bits: &[bool]) -> BigUint {
63 let mut rank = BigUint::from(0u32);
64 for (j, &b) in bits.iter().enumerate() {
65 if b {
66 rank.set_bit(j as u64, true);
67 }
68 }
69 rank
70}
71
72pub fn bit_vector_unrank(rank: &BigUint, width: usize) -> Result<Vec<bool>, CombError> {
74 let bound = BigUint::from(1u32) << width;
75 if rank >= &bound {
76 return Err(CombError::OutOfRange {
77 value: rank.to_string(),
78 bound: bound.to_string(),
79 });
80 }
81 Ok((0..width).map(|j| rank.bit(j as u64)).collect())
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn iterates_all_in_order() {
90 let all: Vec<_> = bit_vectors(2).unwrap().collect();
91 assert_eq!(all.len(), 4);
92 assert_eq!(all[0], vec![false, false]);
93 assert_eq!(all[1], vec![true, false]); assert_eq!(all[3], vec![true, true]);
95 }
96
97 #[test]
98 fn rank_unrank_round_trip() {
99 for (i, bits) in bit_vectors(5).unwrap().enumerate() {
100 let r = bit_vector_rank(&bits);
101 assert_eq!(r, BigUint::from(i as u32));
102 assert_eq!(bit_vector_unrank(&r, 5).unwrap(), bits);
103 }
104 }
105
106 #[test]
107 fn width_limit_enforced() {
108 assert!(matches!(bit_vectors(200), Err(CombError::LimitExceeded(_))));
109 }
110
111 #[test]
112 fn unrank_rejects_cardinality() {
113 assert!(matches!(
114 bit_vector_unrank(&BigUint::from(8u32), 3),
115 Err(CombError::OutOfRange { .. })
116 ));
117 }
118
119 #[test]
120 fn width_127_total_is_exact_domain_size() {
121 let iter = bit_vectors(127).unwrap();
122 assert_eq!(iter.total_ordinals(), 1u128 << 127);
123 assert_eq!(iter.remaining_ordinals(), 1u128 << 127);
124 }
125}