Skip to main content

triblespace_core/query/
variableset.rs

1use std::fmt;
2
3/// A fixed size bitset for up to 128 variables.
4/// The set is represented as a 128-bit integer where each bit
5/// represents the presence of the corresponding element in the set.
6#[derive(Eq, PartialEq, Clone, Copy)]
7#[repr(transparent)]
8pub struct VariableSet {
9    bits: u128,
10}
11
12impl VariableSet {
13    /// Create a new empty set.
14    #[must_use]
15    pub const fn new_empty() -> Self {
16        VariableSet { bits: 0 }
17    }
18    /// Create a new set with every value of the domain set.
19    #[must_use]
20    pub const fn new_full() -> Self {
21        VariableSet { bits: !0 }
22    }
23
24    /// Create a new set with a single value from the domain set.
25    #[must_use]
26    pub fn new_singleton(index: usize) -> Self {
27        let mut set = Self::new_empty();
28        set.set(index);
29        set
30    }
31
32    /// Check if the set is empty.
33    #[must_use]
34    pub fn is_empty(&self) -> bool {
35        self.bits == 0
36    }
37    /// Count the number of elements in the set.
38    #[must_use]
39    pub fn count(&self) -> usize {
40        self.bits.count_ones() as usize
41    }
42    /// Set the given value in the set.
43    pub fn set(&mut self, index: usize) {
44        self.bits |= 1 << index;
45    }
46    /// Remove the given value from the set.
47    pub fn unset(&mut self, index: usize) {
48        self.bits &= !(1 << index);
49    }
50    /// Sets or removes the given element into or from the set
51    /// depending on the passed value.
52    pub fn set_value(&mut self, index: usize, value: bool) {
53        if value {
54            self.set(index);
55        } else {
56            self.unset(index);
57        }
58    }
59    /// Include every value in the domain in the set.
60    pub fn set_all(&mut self) {
61        self.bits = !0;
62    }
63    /// Remove all values from the set.
64    pub fn unset_all(&mut self) {
65        self.bits = 0;
66    }
67    /// Check if the given value is in the set.
68    #[must_use]
69    pub fn is_set(&self, index: usize) -> bool {
70        0 != (self.bits & (1 << index))
71    }
72    /// Finds the index of the first set bit.
73    /// If no bits are set, returns `None`.
74    #[must_use]
75    pub fn find_first_set(&self) -> Option<usize> {
76        if self.bits != 0 {
77            return Some(self.bits.trailing_zeros() as usize);
78        }
79        None
80    }
81    /// Finds the index of the last set bit.
82    /// If no bits are set, returns `None`.
83    #[must_use]
84    pub fn find_last_set(&self) -> Option<usize> {
85        if self.bits != 0 {
86            return Some(127 - (self.bits.leading_zeros() as usize));
87        }
88        None
89    }
90    /// Returns the index of the next set bit
91    /// in the bit set, in ascending order, while unseting it.
92    pub fn drain_next_ascending(&mut self) -> Option<usize> {
93        if let Some(next_index) = self.find_first_set() {
94            self.unset(next_index);
95            Some(next_index)
96        } else {
97            None
98        }
99    }
100    /// Returns the index of the next set bit
101    /// in the bit set, in descending order, while unseting it.
102    pub fn drain_next_descending(&mut self) -> Option<usize> {
103        if let Some(next_index) = self.find_last_set() {
104            self.unset(next_index);
105            Some(next_index)
106        } else {
107            None
108        }
109    }
110    /// Checks if the set is a superset of the passed set.
111    #[must_use]
112    pub fn is_superset_of(&self, other: &Self) -> bool {
113        ((self.bits & other.bits) ^ other.bits) == 0
114    }
115    /// Checks if the set is a subset of the passed set.
116    #[must_use]
117    pub fn is_subset_of(&self, other: &Self) -> bool {
118        ((self.bits & other.bits) ^ self.bits) == 0
119    }
120    /// Compute the set intersection between the two given sets.
121    #[must_use]
122    pub fn intersect(self, other: Self) -> Self {
123        Self {
124            bits: self.bits & other.bits,
125        }
126    }
127    /// Compute the set union between the two given sets.
128    #[must_use]
129    pub fn union(self, other: Self) -> Self {
130        Self {
131            bits: self.bits | other.bits,
132        }
133    }
134    /// Compute the set subtraction between the two given sets.
135    #[must_use]
136    pub fn subtract(self, other: Self) -> Self {
137        Self {
138            bits: self.bits & !other.bits,
139        }
140    }
141    /// Compute the set difference between the two given sets.
142    #[must_use]
143    pub fn difference(self, other: Self) -> Self {
144        Self {
145            bits: self.bits ^ other.bits,
146        }
147    }
148    /// Compute a set complement, removing every element that was in the set
149    /// and inserting every element from the domain that wasn't in the set.
150    #[must_use]
151    pub fn complement(self) -> Self {
152        Self { bits: !self.bits }
153    }
154    /// Remove all elements from the set except the one passed.
155    /// Equal to an intersection with a set containing only the passed element.
156    pub fn keep_single(&mut self, index: usize) {
157        let had_bit = self.is_set(index);
158        self.unset_all();
159        if had_bit {
160            self.set(index);
161        }
162    }
163
164    /// Similar to keep_single, except that only values in the
165    /// specified range are kept. Both range ends are inclusive.
166    pub fn keep_range(&mut self, from_index: usize, to_index: usize) {
167        self.bits &= !0 << from_index;
168        self.bits &= !(!1 << to_index);
169    }
170}
171
172impl fmt::Debug for VariableSet {
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        write!(f, "VariableSet: {{")?;
175        let mut needs_comma = false;
176        for byte in 0..128 {
177            if self.is_set(byte) {
178                if needs_comma {
179                    write!(f, ", ",)?;
180                }
181                write!(f, "{byte}")?;
182                needs_comma = true;
183            }
184        }
185        writeln!(f, "}}")?;
186        Ok(())
187    }
188}
189
190pub struct VariableSetIterator(VariableSet);
191
192impl Iterator for VariableSetIterator {
193    type Item = usize;
194
195    fn next(&mut self) -> Option<Self::Item> {
196        self.0.drain_next_ascending()
197    }
198}
199
200impl IntoIterator for VariableSet {
201    type Item = usize;
202    type IntoIter = VariableSetIterator;
203
204    fn into_iter(self) -> Self::IntoIter {
205        VariableSetIterator(self)
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212    use proptest::prelude::*;
213
214    #[test]
215    fn new_empty_is_empty() {
216        let set = VariableSet::new_empty();
217        assert!(set.is_empty());
218    }
219    #[test]
220    fn new_full_is_not_empty() {
221        let set = VariableSet::new_full();
222        assert!(!set.is_empty());
223    }
224    #[test]
225    fn after_set_is_not_empty() {
226        let mut set = VariableSet::new_empty();
227        set.set(5);
228        assert!(!set.is_empty());
229    }
230    #[test]
231    fn after_set_unset_is_empty() {
232        let mut set = VariableSet::new_empty();
233        set.set(5);
234        set.unset(5);
235        assert!(set.is_empty());
236    }
237    #[test]
238    fn after_set_is_set() {
239        let mut set = VariableSet::new_empty();
240        set.set(5);
241        assert!(set.is_set(5));
242    }
243    #[test]
244    fn after_unset_is_not_set() {
245        let mut set = VariableSet::new_full();
246        set.unset(5);
247        assert!(!set.is_set(5));
248    }
249    #[test]
250    fn find_first_set_none() {
251        let set = VariableSet::new_empty();
252        assert_eq!(None, set.find_first_set());
253    }
254    #[test]
255    fn find_last_set_none() {
256        let set = VariableSet::new_empty();
257        assert_eq!(None, set.find_last_set());
258    }
259    #[test]
260    fn superset_full_of_empty() {
261        let empty = VariableSet::new_empty();
262        let full = VariableSet::new_full();
263        assert!(full.is_superset_of(&empty));
264    }
265    #[test]
266    fn superset_not_empty_of_full() {
267        let empty = VariableSet::new_empty();
268        let full = VariableSet::new_full();
269        assert!(!empty.is_superset_of(&full));
270    }
271    #[test]
272    fn subset_empty_of_full() {
273        let empty = VariableSet::new_empty();
274        let full = VariableSet::new_full();
275        assert!(empty.is_subset_of(&full));
276    }
277    #[test]
278    fn subset_not_full_of_empty() {
279        let empty = VariableSet::new_empty();
280        let full = VariableSet::new_full();
281        assert!(!full.is_subset_of(&empty));
282    }
283    proptest! {
284        #[test]
285        fn find_first_set(n in 0..128usize) {
286            let mut set = VariableSet::new_empty();
287            set.set(n);
288            prop_assert_eq!(Some(n), set.find_first_set());
289        }
290        #[test]
291        fn find_last_set(n in 0..128usize) {
292            let mut set = VariableSet::new_empty();
293            set.set(n);
294            prop_assert_eq!(Some(n), set.find_last_set());
295        }
296        #[test]
297        fn drain_ascending_drains(n in 0..128usize) {
298            let mut set = VariableSet::new_empty();
299            set.set(n);
300            prop_assert_eq!(Some(n), set.drain_next_ascending());
301            prop_assert!(!set.is_set(n));
302        }
303        #[test]
304        fn drain_descending_drains(n in 0..128usize) {
305            let mut set = VariableSet::new_empty();
306            set.set(n);
307            prop_assert_eq!(Some(n), set.drain_next_descending());
308            prop_assert!(!set.is_set(n));
309        }
310        #[test]
311        fn intersect(n in 0..128usize, m in 0..128usize) {
312            let mut left = VariableSet::new_empty();
313            let mut right = VariableSet::new_empty();
314            left.set(n);
315            right.set(m);
316
317            let out = left.intersect(right);
318            prop_assert_eq!(n == m, out.is_set(n));
319        }
320        #[test]
321        fn union(n in 0..128usize, m in 0..128usize) {
322            let mut left = VariableSet::new_empty();
323            let mut right = VariableSet::new_empty();
324            left.set(n);
325            right.set(m);
326
327            let out = left.union(right);
328            prop_assert!(out.is_set(n));
329            prop_assert!(out.is_set(m));
330        }
331        #[test]
332        fn subtract(n in 0..128usize, m in 0..128usize) {
333            let mut left = VariableSet::new_empty();
334            let mut right = VariableSet::new_empty();
335            left.set(n);
336            right.set(m);
337
338            let out = left.subtract(right);
339            prop_assert_eq!(n != m, out.is_set(n));
340        }
341        #[test]
342        fn difference(n in 0..128usize, m in 0..128usize) {
343            let mut left = VariableSet::new_empty();
344            let mut right = VariableSet::new_empty();
345            left.set(n);
346            right.set(m);
347
348            let out = left.difference(right);
349            prop_assert_eq!(n != m, out.is_set(n));
350            prop_assert_eq!(n != m, out.is_set(m));
351        }
352        #[test]
353        fn complement(n in 0..128usize, m in 0..128usize) {
354            let mut input = VariableSet::new_empty();
355            input.set(n);
356
357            let out = input.complement();
358            prop_assert!(!out.is_set(n));
359            if n != m {
360                prop_assert!(out.is_set(m));
361            }
362        }
363        #[test]
364        fn keep_single(n in 0..128usize, m in 0..128usize) {
365            let mut set = VariableSet::new_full();
366            set.keep_single(n);
367            prop_assert!(set.is_set(n));
368            if n != m {
369                prop_assert!(!set.is_set(m));
370            }
371        }
372        #[test]
373        fn keep_range(from in 0..128usize, to in 0..128usize) {
374            let mut set = VariableSet::new_full();
375            set.keep_range(from, to);
376
377            for n in 0..128 {
378                prop_assert_eq!(from <= n && n <= to, set.is_set(n));
379            }
380        }
381    }
382}