dtrees_rs/cover/
reversible_cover.rs1use crate::bitsets::Bitset;
4use search_trail::{
5 ReversibleU64, ReversibleUsize, SaveAndRestore, StateManager, U64Manager, UsizeManager,
6};
7use std::cmp::Ordering;
8use std::ops::Sub;
9
10pub struct SparseBitset {
15 words: Vec<ReversibleU64>,
16 non_zero_words: Vec<usize>,
17 nb_non_zero: ReversibleUsize,
18
19 state_manager: StateManager,
20}
21
22#[derive(Debug)]
25pub struct ShallowBitset {
26 words: Vec<u64>,
27}
28
29#[derive(Default)]
32pub struct Difference {
33 pub(crate) in_count: usize,
34 pub(crate) out_count: usize,
35}
36
37impl SparseBitset {
38 pub fn new(n: usize) -> Self {
40 let mut state_manager = StateManager::default();
41
42 let nb_words = n.div_ceil(64);
43 let mut words = Vec::with_capacity(nb_words);
44 for _ in 0..nb_words {
45 words.push(state_manager.manage_u64(u64::MAX));
46 }
47
48 let mask = if n % 64 == 0 {
49 u64::MAX
50 } else {
51 (1u64 << (n % 64)) - 1
52 };
53 if let Some(last) = words.last_mut() {
54 state_manager.set_u64(*last, mask);
55 }
56 let non_zero_words = (0..nb_words).collect();
57 let nb_non_zero = state_manager.manage_usize(nb_words);
58
59 state_manager.save_state();
60
61 Self {
62 words,
63 non_zero_words,
64 nb_non_zero,
65 state_manager,
66 }
67 }
68
69 pub fn count(&self) -> usize {
71 let mut count = 0;
72 let nb_non_zero = self.state_manager.get_usize(self.nb_non_zero);
73 for i in (0..nb_non_zero).rev() {
74 count += self
75 .state_manager
76 .get_u64(self.words[self.non_zero_words[i]])
77 .count_ones();
78 }
79 count as usize
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.state_manager.get_usize(self.nb_non_zero) == 0
85 }
86
87 pub fn intersect_with(&mut self, other: &Bitset, invert: bool) -> usize {
90 self.state_manager.save_state();
91
92 let mut size = self.state_manager.get_usize(self.nb_non_zero);
93 let mut count = 0;
94 for i in (0..size).rev() {
95 let idx = self.non_zero_words[i];
96 let intersect = self.state_manager.get_u64(self.words[idx])
97 & if invert { !other[idx] } else { other[idx] };
98 if intersect == 0 {
99 size -= 1;
100 self.non_zero_words[i] = self.non_zero_words[size];
101 self.non_zero_words[size] = idx;
102 } else {
103 self.state_manager.set_u64(self.words[idx], intersect);
104 count += intersect.count_ones();
105 }
106 }
107 self.state_manager.set_usize(self.nb_non_zero, size);
108
109 count as usize
110 }
111
112 pub fn count_intersect_with(&self, other: &Bitset, invert: bool) -> usize {
115 let size = self.state_manager.get_usize(self.nb_non_zero);
116 let mut count = 0;
117 for i in (0..size).rev() {
118 let idx = self.non_zero_words[i];
119 let intersect = self.state_manager.get_u64(self.words[idx])
120 & if invert { !other[idx] } else { other[idx] };
121 if intersect != 0 {
122 count += intersect.count_ones();
123 }
124 }
125 count as usize
126 }
127
128 pub fn count_intersect_with_many(&self, others: &[Bitset]) -> Vec<usize> {
130 let mut counts = vec![0; others.len()];
131 let size = self.state_manager.get_usize(self.nb_non_zero);
132 for i in (0..size).rev() {
133 let idx = self.non_zero_words[i];
134 let word = self.state_manager.get_u64(self.words[idx]);
135 for (bid, other) in others.iter().enumerate() {
136 counts[bid] += (word & other[idx]).count_ones() as usize
137 }
138 }
139 counts
140 }
141
142 pub fn to_vec(&self) -> Vec<usize> {
144 let mut result = Vec::new();
145 let nb_non_zero = self.state_manager.get_usize(self.nb_non_zero);
146
147 for i in 0..nb_non_zero {
148 let word_idx = self.non_zero_words[i];
149 let mut word = self.state_manager.get_u64(self.words[word_idx]);
150 let base_idx = word_idx * 64;
151
152 while word != 0 {
153 let bit_pos = word.trailing_zeros() as usize;
154 result.push(base_idx + bit_pos);
155 word &= word - 1;
156 }
157 }
158 result
159 }
160
161 #[inline]
163 pub fn restore(&mut self) {
164 self.state_manager.restore_state();
165 }
166
167 fn active_words(&self) -> Vec<u64> {
169 let mut words = Vec::new();
170 self.write_active_words(&mut words);
171 words
172 }
173
174 pub fn write_active_words(&self, out: &mut Vec<u64>) {
180 out.clear();
181 out.resize(self.words.len(), 0);
182 let nb_non_zero = self.state_manager.get_usize(self.nb_non_zero);
183 for &idx in &self.non_zero_words[..nb_non_zero] {
184 out[idx] = self.state_manager.get_u64(self.words[idx]);
185 }
186 }
187}
188
189impl From<&SparseBitset> for ShallowBitset {
190 fn from(val: &SparseBitset) -> Self {
191 ShallowBitset {
192 words: val.active_words(),
193 }
194 }
195}
196
197impl Sub<&ShallowBitset> for &SparseBitset {
200 type Output = Difference;
201 fn sub(self, rhs: &ShallowBitset) -> Self::Output {
202 let words = self.active_words();
203 let in_count = words
204 .iter()
205 .zip(&rhs.words)
206 .map(|(&own, &other)| (own & !other).count_ones() as usize)
207 .sum();
208 let out_count = words
209 .iter()
210 .zip(&rhs.words)
211 .map(|(&own, &other)| (other & !own).count_ones() as usize)
212 .sum();
213 Difference {
214 in_count,
215 out_count,
216 }
217 }
218}
219
220impl Sub<ShallowBitset> for SparseBitset {
221 type Output = Difference;
222
223 fn sub(self, rhs: ShallowBitset) -> Self::Output {
224 &self - &rhs
225 }
226}
227impl Sub<&ShallowBitset> for SparseBitset {
228 type Output = Difference;
229
230 fn sub(self, rhs: &ShallowBitset) -> Self::Output {
231 &self - rhs
232 }
233}
234
235impl Sub<ShallowBitset> for &SparseBitset {
236 type Output = Difference;
237
238 fn sub(self, rhs: ShallowBitset) -> Self::Output {
239 self - &rhs
240 }
241}
242
243impl Ord for Difference {
244 fn cmp(&self, other: &Self) -> Ordering {
245 (self.in_count + self.out_count).cmp(&(other.in_count + other.out_count))
246 }
247}
248
249impl PartialOrd for Difference {
250 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
251 Some(self.cmp(other))
252 }
253}
254
255impl PartialEq for Difference {
256 fn eq(&self, other: &Self) -> bool {
257 (self.in_count + self.out_count) == (other.in_count + other.out_count)
258 }
259}
260
261impl Eq for Difference {}
262
263#[cfg(test)]
264mod sparse_test {
265 use crate::bitsets::{BitCollection, Bitset, BitsetInit};
266 use crate::cover::reversible_cover::{ShallowBitset, SparseBitset};
267 use search_trail::UsizeManager;
268
269 #[test]
270 fn create() {
271 let mut cover = SparseBitset::new(10);
272
273 let mut feature = Bitset::new(BitsetInit::Empty(10));
274
275 feature.set(9);
276
277 println!("{:?}", cover.to_vec());
278 assert_eq!(cover.count(), 10);
279
280 cover.intersect_with(&feature, false);
281 println!("{:?}", cover.to_vec());
282 println!("xx {:?}", cover.state_manager.get_usize(cover.nb_non_zero));
283
284 let shallow_cover: ShallowBitset = (&cover).into();
285 println!("Shaloow {:?}", shallow_cover);
286 cover.restore();
287 println!("{:?}", cover.to_vec());
288
289 let _ = &cover - shallow_cover;
290 }
291
292 #[test]
293 fn a_word_emptied_by_an_intersection_counts_as_empty() {
294 let mut feature = Bitset::new(BitsetInit::Empty(128));
297 for row in 64..128 {
298 feature.set(row);
299 }
300 let mut cover = SparseBitset::new(128);
301 let full: ShallowBitset = (&cover).into();
302 cover.intersect_with(&feature, false);
303
304 let difference = &cover - &full;
305 assert_eq!(difference.in_count, 0);
306 assert_eq!(difference.out_count, 64, "rows 0..64 are only in `full`");
307
308 let half: ShallowBitset = (&cover).into();
309 cover.restore();
310 let difference = &cover - ½
311 assert_eq!(difference.in_count, 64, "rows 0..64 are only in `cover`");
312 assert_eq!(difference.out_count, 0);
313 }
314}