pub struct BitSet {
size: usize,
bits: Vec<Block>,
}Fields§
§size: usize§bits: Vec<Block>Implementations§
Source§impl BitSet
impl BitSet
Sourcepub fn new(size: usize) -> Self
pub fn new(size: usize) -> Self
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 23)
20 pub fn zeros(shape: (usize, usize)) -> Self {
21 Self {
22 shape,
23 data: vec![BitSet::new(shape.1); shape.0],
24 }
25 }
26
27 pub fn from_vec(data: Vec<BitSet>) -> Self {
28 let shape = (data.len(), data.first().map_or(0, BitSet::len));
29 assert!(data.iter().all(|row| row.len() == shape.1));
30 Self { shape, data }
31 }
32
33 pub fn new_with(shape: (usize, usize), mut f: impl FnMut(usize, usize) -> bool) -> Self {
34 let mut a = Self::zeros(shape);
35 for (i, row) in a.data.iter_mut().enumerate() {
36 for (w, word) in row.words_mut().iter_mut().enumerate() {
37 for j in w * 64..shape.1.min((w + 1) * 64) {
38 *word |= u64::from(f(i, j)) << (j & 63);
39 }
40 }
41 }
42 a
43 }
44
45 pub fn eye(shape: (usize, usize)) -> Self {
46 let mut a = Self::zeros(shape);
47 for i in 0..shape.0.min(shape.1) {
48 a[i].set(i, true);
49 }
50 a
51 }
52
53 pub fn transpose(&self) -> Self {
54 let mut a = Self::zeros((self.shape.1, self.shape.0));
55 for (i, row) in self.data.iter().enumerate() {
56 for j in row.iter_ones() {
57 a[j].set(i, true);
58 }
59 }
60 a
61 }
62
63 /// Replaces the matrix with reduced row echelon form and returns its pivot columns.
64 pub fn row_reduction(&mut self) -> Vec<usize> {
65 self.eliminate(self.shape.1, true, false)
66 }
67
68 /// Replaces the matrix with row echelon form and returns its rank.
69 pub fn rank(&mut self) -> usize {
70 self.eliminate(self.shape.1, false, false).len()
71 }
72
73 /// Computes the determinant in place. The matrix must be square.
74 pub fn determinant(&mut self) -> bool {
75 assert_eq!(self.shape.0, self.shape.1);
76 self.eliminate(self.shape.1, false, true).len() == self.shape.0
77 }
78
79 /// Returns the inverse, or `None` if singular. The matrix must be square.
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }
138
139 pub fn pow(self, mut n: usize) -> Self {
140 assert_eq!(self.shape.0, self.shape.1);
141 let mut result = Self::eye(self.shape);
142 let mut a = self;
143 while n != 0 {
144 if n & 1 != 0 {
145 result = &result * &a;
146 }
147 n >>= 1;
148 if n != 0 {
149 a = &a * &a;
150 }
151 }
152 result
153 }
154
155 fn eliminate(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
156 #[cfg(target_arch = "x86_64")]
157 match simd_backend() {
158 // SAFETY: the dispatcher checks the required CPU features.
159 SimdBackend::Avx512 => {
160 return unsafe { self.eliminate_avx512(cols, full, require_full_rank) };
161 }
162 // SAFETY: the dispatcher checks AVX2 support.
163 SimdBackend::Avx2 => {
164 return unsafe { self.eliminate_avx2(cols, full, require_full_rank) };
165 }
166 SimdBackend::Scalar => {}
167 }
168 self.eliminate_impl(cols, full, require_full_rank)
169 }
170
171 // Inlined into each target-feature entry point to vectorize the row operations.
172 #[inline(always)]
173 fn eliminate_impl(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
174 let n = self.shape.0;
175 let mut pivots = Vec::with_capacity(n.min(cols));
176 if n < 32 {
177 let mut c = 0;
178 while c < cols {
179 let r = pivots.len();
180 if r == n {
181 break;
182 }
183 let Some(p) = (r..n).find(|&i| self[i].get(c)) else {
184 if require_full_rank {
185 return pivots;
186 }
187 c = self.next_column(r, c + 1, cols);
188 continue;
189 };
190 self.data.swap(r, p);
191 let (upper, lower) = self.data.split_at_mut(r);
192 let (pivot, lower) = lower.split_first_mut().unwrap();
193 for row in lower
194 .iter_mut()
195 .chain(upper.iter_mut().take(if full { r } else { 0 }))
196 {
197 if row.get(c) {
198 xor(&mut row.words_mut()[c / 64..], &pivot.words()[c / 64..]);
199 }
200 }
201 pivots.push(c);
202 c += 1;
203 }
204 return pivots;
205 }
206 // Eliminating a shared leading coefficient preserves the two-coefficient bound.
207 if self
208 .data
209 .iter()
210 .all(|row| row.iter_ones().take_while(|&c| c < cols).take(3).count() <= 2)
211 {
212 return self.eliminate_sparse(cols, full, require_full_rank);
213 }
214 let block: usize = if n < 512 {
215 4
216 } else if n < 1536 {
217 8
218 } else {
219 32
220 };
221 let mut table = vec![BitSet::new(self.shape.1); (1 << block.min(8)) * block.div_ceil(8)];
222 let mut reduced = vec![0; n];
223 let mut start = 0;
224 while start < cols {
225 let first = pivots.len();
226 let word = start / 64;
227 reduced.fill(first);
228 let end = cols.min(start + block);
229 let mut c = start;
230 while c < end {
231 let r = pivots.len();
232 let mut pivot = None;
233 for (i, reduced) in reduced.iter_mut().enumerate().skip(r) {
234 let (upper, lower) = self.data.split_at_mut(i);
235 let row = &mut lower[0];
236 for p in *reduced..r {
237 if row.get(pivots[p]) {
238 xor(&mut row.words_mut()[word..], &upper[p].words()[word..]);
239 }
240 }
241 *reduced = r;
242 if row.get(c) {
243 pivot = Some(i);
244 break;
245 }
246 }
247 if let Some(p) = pivot {
248 self.data.swap(r, p);
249 reduced.swap(r, p);
250 pivots.push(c);
251 c += 1;
252 } else if require_full_rank {
253 return pivots;
254 } else {
255 c = self.next_column(r, c + 1, end);
256 }
257 }
258 let rank = pivots.len();
259 if first == rank {
260 let next = self.next_column(rank, start + block, cols);
261 if next == cols {
262 break;
263 }
264 start = next / block * block;
265 continue;
266 }
267 // Make the panel's pivot columns an identity matrix before indexing its table.
268 for r in (first..rank).rev() {
269 let (upper, lower) = self.data.split_at_mut(r);
270 for row in &mut upper[first..] {
271 if row.get(pivots[r]) {
272 xor(&mut row.words_mut()[word..], &lower[0].words()[word..]);
273 }
274 }
275 }
276 let mut indices = [[0usize; 256]; 4];
277 let mut masks = [0usize; 4];
278 for group in 0..block.div_ceil(8) {
279 let mut keys = [0usize; 256];
280 let mut count = 0;
281 for (row, &c) in pivots[first..].iter().enumerate() {
282 if (c - start) / 8 != group {
283 continue;
284 }
285 let half = 1 << count;
286 count += 1;
287 for index in 0..half {
288 keys[index + half] = keys[index] | (1 << ((c - start) % 8));
289 let (lower, upper) = table.split_at_mut(group * 256 + index + half);
290 let target = &mut upper[0].words_mut()[word..];
291 let source = &lower[group * 256 + index].words()[word..];
292 let pivot = &self[first + row].words()[word..];
293 for ((x, y), z) in target.iter_mut().zip(source).zip(pivot) {
294 *x = y ^ z;
295 }
296 }
297 }
298 masks[group] = keys[(1 << count) - 1];
299 for (i, &key) in keys[..1 << count].iter().enumerate() {
300 indices[group][key] = i;
301 }
302 }
303 for i in (rank..n).chain(0..if full { first } else { 0 }) {
304 let key = (self[i].words()[word] >> (start & 63)) as usize;
305 let x = indices[0][key & masks[0]];
306 if block <= 8 {
307 if x != 0 {
308 xor(&mut self[i].words_mut()[word..], &table[x].words()[word..]);
309 }
310 continue;
311 }
312 let y = indices[1][(key >> 8) & masks[1]];
313 let z = indices[2][(key >> 16) & masks[2]];
314 let w = indices[3][(key >> 24) & masks[3]];
315 if x | y | z | w != 0 {
316 let p = &table[x].words()[word..];
317 let q = &table[256 + y].words()[word..];
318 let r = &table[512 + z].words()[word..];
319 let s = &table[768 + w].words()[word..];
320 for ((((x, y), z), r), s) in self[i].words_mut()[word..]
321 .iter_mut()
322 .zip(p)
323 .zip(q)
324 .zip(r)
325 .zip(s)
326 {
327 *x ^= y ^ z ^ r ^ s;
328 }
329 }
330 }
331 if rank == n {
332 break;
333 }
334 start += block;
335 }
336 pivots
337 }
338
339 fn next_column(&self, row: usize, mut start: usize, cols: usize) -> usize {
340 while start < cols {
341 let word = start / 64;
342 let bits = self.data[row..]
343 .iter()
344 .fold(0, |x, row| x | row.words()[word])
345 & (u64::MAX << (start & 63));
346 if bits != 0 {
347 return (word * 64 + bits.trailing_zeros() as usize).min(cols);
348 }
349 start = (word + 1) * 64;
350 }
351 cols
352 }
353
354 #[inline(always)]
355 fn eliminate_sparse(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
356 let n = self.shape.0;
357 let mut basis = vec![n; cols];
358 let mut pivots = Vec::new();
359 for i in 0..n {
360 loop {
361 let Some(c) = self[i].iter_ones().next().filter(|&c| c < cols) else {
362 if require_full_rank {
363 return pivots;
364 }
365 break;
366 };
367 if basis[c] == n {
368 basis[c] = i;
369 pivots.push(c);
370 break;
371 }
372 let (upper, lower) = self.data.split_at_mut(i);
373 xor(
374 &mut lower[0].words_mut()[c / 64..],
375 &upper[basis[c]].words()[c / 64..],
376 );
377 }
378 }
379 pivots.sort_unstable();
380 self.data
381 .sort_by_cached_key(|row| row.iter_ones().next().filter(|&c| c < cols).unwrap_or(cols));
382 if full {
383 for (i, &c) in pivots.iter().enumerate() {
384 basis[c] = i;
385 }
386 for i in (0..pivots.len()).rev() {
387 let next = self[i].iter_ones().take_while(|&c| c < cols).nth(1);
388 if let Some(c) = next
389 && basis[c] != n
390 {
391 let (upper, lower) = self.data.split_at_mut(basis[c]);
392 xor(
393 &mut upper[i].words_mut()[c / 64..],
394 &lower[0].words()[c / 64..],
395 );
396 }
397 }
398 }
399 pivots
400 }
401
402 #[inline(always)]
403 fn mul_impl(&self, rhs: &Self) -> Self {
404 let mut result = Self::zeros((self.shape.0, rhs.shape.1));
405 let ones = self.data.iter().map(BitSet::count_ones).sum::<u64>();
406 let size = self.shape.0 as u64 * self.shape.1 as u64;
407 if self.shape.0 < 256 || self.shape.1 < 32 || ones <= size / 8 {
408 for (a, c) in self.data.iter().zip(&mut result.data) {
409 for j in a.iter_ones() {
410 xor(c.words_mut(), rhs[j].words());
411 }
412 }
413 return result;
414 }
415 if size - ones <= size / 8 {
416 let mut sum = BitSet::new(rhs.shape.1);
417 for row in &rhs.data {
418 sum ^= row;
419 }
420 for (a, c) in self.data.iter().zip(&mut result.data) {
421 c.words_mut().copy_from_slice(sum.words());
422 for j in (!a.clone()).iter_ones() {
423 xor(c.words_mut(), rhs[j].words());
424 }
425 }
426 return result;
427 }
428 let width = rhs.shape.1.div_ceil(64);
429 if width == 0 {
430 return result;
431 }
432
433 // Separate the table groups by a cache line to avoid mapping them to the same sets.
434 let group = 256 * width + 8;
435 let mut storage = BitSet::new(8 * group * 64);
436 let table = storage.words_mut();
437 for start in (0..self.shape.1).step_by(64) {
438 for (t, table) in table.chunks_exact_mut(group).enumerate() {
439 let col = start + t * 8;
440 for bit in 0..self.shape.1.saturating_sub(col).min(8) {
441 let row = rhs[col + bit].words();
442 let half = (1 << bit) * width;
443 let (lower, upper) = table.split_at_mut(half);
444 for (source, dest) in
445 lower.chunks_exact(width).zip(upper.chunks_exact_mut(width))
446 {
447 for ((x, y), z) in dest.iter_mut().zip(source).zip(row) {
448 *x = y ^ z;
449 }
450 }
451 }
452 }
453 for (a, c) in self.data.iter().zip(&mut result.data) {
454 let key = a.words()[start / 64];
455 let offset = (key & 255) as usize * width;
456 let p0 = &table[offset..offset + width];
457 let offset = group + (key >> 8 & 255) as usize * width;
458 let p1 = &table[offset..offset + width];
459 let offset = 2 * group + (key >> 16 & 255) as usize * width;
460 let p2 = &table[offset..offset + width];
461 let offset = 3 * group + (key >> 24 & 255) as usize * width;
462 let p3 = &table[offset..offset + width];
463 let offset = 4 * group + (key >> 32 & 255) as usize * width;
464 let p4 = &table[offset..offset + width];
465 let offset = 5 * group + (key >> 40 & 255) as usize * width;
466 let p5 = &table[offset..offset + width];
467 let offset = 6 * group + (key >> 48 & 255) as usize * width;
468 let p6 = &table[offset..offset + width];
469 let offset = 7 * group + (key >> 56 & 255) as usize * width;
470 let p7 = &table[offset..offset + width];
471 for ((((((((x, p0), p1), p2), p3), p4), p5), p6), p7) in c
472 .words_mut()
473 .iter_mut()
474 .zip(p0)
475 .zip(p1)
476 .zip(p2)
477 .zip(p3)
478 .zip(p4)
479 .zip(p5)
480 .zip(p6)
481 .zip(p7)
482 {
483 *x ^= p0 ^ p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ p7;
484 }
485 }
486 }
487 result
488 }More examples
crates/competitive/src/data_structure/bitset.rs (line 47)
45 pub fn from_binary(s: &str) -> Option<Self> {
46 let bytes = s.as_bytes();
47 let mut bits = Self::new(bytes.len());
48 let end = bytes.len() / 64 * 64;
49 #[cfg(target_arch = "x86_64")]
50 let parsed = if avx512_enabled() && is_x86_feature_detected!("avx512bw") {
51 // SAFETY: AVX-512BW is available; each complete chunk contains 64 bytes.
52 unsafe { simd::parse_binary_avx512(&bytes[..end], bits.words_mut()) }
53 } else if is_x86_feature_detected!("avx2") {
54 // SAFETY: AVX2 is available; each complete chunk contains 64 bytes.
55 unsafe { simd::parse_binary_avx2(&bytes[..end], bits.words_mut()) }
56 } else {
57 Self::parse_binary_scalar(&bytes[..end], bits.words_mut())
58 };
59 #[cfg(not(target_arch = "x86_64"))]
60 let parsed = Self::parse_binary_scalar(&bytes[..end], bits.words_mut());
61 if !parsed {
62 return None;
63 }
64 if end != bytes.len() {
65 let mut word = 0;
66 for (i, &b) in bytes[end..].iter().enumerate() {
67 if b != b'0' && b != b'1' {
68 return None;
69 }
70 word |= u64::from(b & 1) << i;
71 }
72 bits.words_mut()[end / 64] = word;
73 }
74 Some(bits)
75 }
76
77 fn parse_binary_scalar(bytes: &[u8], words: &mut [u64]) -> bool {
78 for (chunk, word) in bytes.as_chunks::<64>().0.iter().zip(words) {
79 for (i, byte) in chunk.as_chunks::<8>().0.iter().enumerate() {
80 let x = u64::from_le_bytes(*byte);
81 if x & 0xfefe_fefe_fefe_fefe != 0x3030_3030_3030_3030 {
82 return false;
83 }
84 *word |= ((x & 0x0101_0101_0101_0101).wrapping_mul(0x0102_0408_1020_4080) >> 56)
85 << (i * 8);
86 }
87 }
88 true
89 }
90
91 /// Returns ASCII `0` and `1` in increasing bit-index order.
92 pub fn to_binary(&self) -> String {
93 const TABLE: [[u8; 8]; 256] = {
94 let mut table = [[b'0'; 8]; 256];
95 let mut i = 0;
96 while i < 256 {
97 let mut j = 0;
98 while j < 8 {
99 table[i][j] |= ((i >> j) & 1) as u8;
100 j += 1;
101 }
102 i += 1;
103 }
104 table
105 };
106 let mut bytes = vec![b'0'; self.size.div_ceil(8) * 8];
107 #[cfg(target_arch = "x86_64")]
108 let end = if self.size >= 64 && avx512_enabled() && is_x86_feature_detected!("avx512bw") {
109 let end = self.size / 64 * 64;
110 // SAFETY: AVX-512BW is available; each output chunk holds one 64-bit word.
111 unsafe {
112 simd::write_binary_avx512(&mut bytes[..end], self.words());
113 }
114 end
115 } else if self.size >= 64 && is_x86_feature_detected!("avx2") {
116 let end = self.size / 64 * 64;
117 // SAFETY: AVX2 is available; each output chunk holds one complete 64-bit word.
118 unsafe {
119 simd::write_binary_avx2(&mut bytes[..end], self.words());
120 }
121 end
122 } else {
123 0
124 };
125 #[cfg(not(target_arch = "x86_64"))]
126 let end = 0;
127 for (chunk, &word) in bytes[end..].chunks_mut(64).zip(&self.words()[end / 64..]) {
128 for (i, byte) in chunk.as_chunks_mut::<8>().0.iter_mut().enumerate() {
129 byte.copy_from_slice(&TABLE[(word >> (i * 8) & 255) as usize]);
130 }
131 }
132 bytes.truncate(self.size);
133 // SAFETY: every output byte is ASCII `0` or `1`.
134 unsafe { String::from_utf8_unchecked(bytes) }
135 }
136
137 pub fn ones(size: usize) -> Self {
138 let mut self_ = Self {
139 size,
140 bits: vec![Block([u64::MAX; 8]); size.div_ceil(512)],
141 };
142 self_.trim();
143 self_
144 }
145
146 pub fn get(&self, i: usize) -> bool {
147 self.bits[i >> 9].0[i >> 6 & 7] & (1 << (i & 63)) != 0
148 }
149
150 pub fn set(&mut self, i: usize, b: bool) {
151 let word = &mut self.bits[i >> 9].0[i >> 6 & 7];
152 if b {
153 *word |= 1 << (i & 63);
154 } else {
155 *word &= !(1 << (i & 63));
156 }
157 }
158
159 /// Clears all bits.
160 pub fn reset(&mut self) {
161 self.bits.fill(Block::default());
162 }
163
164 /// Sets all bits to `value`.
165 pub fn fill(&mut self, value: bool) {
166 self.bits.fill(Block([if value { u64::MAX } else { 0 }; 8]));
167 self.trim();
168 }
169
170 /// Tests whether any bit is set.
171 #[inline]
172 pub fn any(&self) -> bool {
173 !self.none()
174 }
175
176 /// Tests whether all bits are unset.
177 #[inline]
178 pub fn none(&self) -> bool {
179 #[cfg(target_arch = "x86_64")]
180 if self.bits.len() >= SIMD_MIN_BLOCKS {
181 if self.bits[0].0[0] != 0 {
182 return false;
183 }
184 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
185 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
186 return unsafe { simd::none_avx512(&self.bits) };
187 }
188 if is_x86_feature_detected!("avx2") {
189 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
190 return unsafe { simd::none_avx2(&self.bits) };
191 }
192 }
193 self.words().iter().all(|&word| word == 0)
194 }
195
196 /// Tests whether all bits are set.
197 #[inline(always)]
198 pub fn all(&self) -> bool {
199 let words = self.words();
200 let full_words = self.size >> 6;
201 #[cfg(target_arch = "x86_64")]
202 if self.size >> 9 >= SIMD_MIN_BLOCKS {
203 let full_blocks = self.size >> 9;
204 if words[0] != u64::MAX {
205 return false;
206 }
207 let full_blocks_are_set = if avx512_enabled() && is_x86_feature_detected!("avx512f") {
208 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
209 Some(unsafe { simd::all_avx512(&self.bits[..full_blocks]) })
210 } else if is_x86_feature_detected!("avx2") {
211 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
212 Some(unsafe { simd::all_avx2(&self.bits[..full_blocks]) })
213 } else {
214 None
215 };
216 if let Some(full_blocks_are_set) = full_blocks_are_set {
217 return full_blocks_are_set
218 && words[full_blocks * 8..full_words]
219 .iter()
220 .all(|&word| word == u64::MAX)
221 && (self.size & 63 == 0
222 || words[full_words] == u64::MAX >> (64 - (self.size & 63)));
223 }
224 }
225 if self.size & 63 == 0 {
226 return words.iter().all(|&word| word == u64::MAX);
227 }
228 words[..full_words].iter().all(|&word| word == u64::MAX)
229 && words[full_words] == u64::MAX >> (64 - (self.size & 63))
230 }
231
232 /// Iterates over set-bit indices in ascending order.
233 pub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_ {
234 self.words()
235 .iter()
236 .copied()
237 .enumerate()
238 .flat_map(|(word_index, mut word)| {
239 std::iter::from_fn(move || {
240 if word == 0 {
241 None
242 } else {
243 let bit = word.trailing_zeros() as usize;
244 word &= word - 1;
245 Some((word_index << 6) | bit)
246 }
247 })
248 })
249 }
250
251 /// Counts set bits.
252 #[inline]
253 pub fn count_ones(&self) -> u64 {
254 let words = self.words();
255 #[cfg(target_arch = "x86_64")]
256 if words.len() >= 8 {
257 if avx512_enabled()
258 && is_x86_feature_detected!("avx512f")
259 && is_x86_feature_detected!("avx512vpopcntdq")
260 {
261 // SAFETY: blocks are aligned and feature detection checked both requirements.
262 return unsafe { simd::count_ones_avx512(&self.bits) };
263 }
264 if is_x86_feature_detected!("avx2") {
265 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
266 return unsafe { simd::count_ones_avx2(&self.bits) };
267 }
268 }
269 words.iter().map(|word| word.count_ones() as u64).sum()
270 }
271
272 /// Counts unset bits.
273 #[inline]
274 pub fn count_zeros(&self) -> u64 {
275 self.size as u64 - self.count_ones()
276 }
277
278 pub fn push(&mut self, b: bool) {
279 if self.size & 511 == 0 {
280 self.bits.push(Block::default());
281 }
282 if b {
283 self.bits[self.size >> 9].0[self.size >> 6 & 7] |= 1 << (self.size & 63);
284 }
285 self.size += 1;
286 }
287
288 pub fn resize(&mut self, new_size: usize) {
289 match self.size.cmp(&new_size) {
290 Ordering::Less => self.bits.resize(new_size.div_ceil(512), Block::default()),
291 Ordering::Equal => {}
292 Ordering::Greater => self.bits.truncate(new_size.div_ceil(512)),
293 }
294 self.size = new_size;
295 self.trim();
296 }
297
298 /// Assigns `self | (self << rhs)` to `self`.
299 #[inline]
300 pub fn shl_bitor_assign(&mut self, rhs: usize) {
301 self.shift_left::<true>(rhs);
302 }
303
304 /// Assigns `self | (self >> rhs)` to `self`.
305 #[inline]
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }
364
365 #[inline]
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }
492}
493
494impl Extend<bool> for BitSet {
495 fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T) {
496 for bit in iter {
497 self.push(bit);
498 }
499 }
500}
501
502impl FromIterator<bool> for BitSet {
503 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
504 let mut set = BitSet::new(0);
505 set.extend(iter);
506 set
507 }Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Examples found in repository?
crates/competitive/src/combinatorial_optimization/subset_sum_problem.rs (line 40)
38 pub fn contains(&mut self, sum: usize) -> bool {
39 self.rebuild();
40 if sum < self.dp.len() {
41 self.dp.get(sum)
42 } else {
43 false
44 }
45 }
46
47 fn rebuild(&mut self) {
48 if self.pending_weights.is_empty() {
49 return;
50 }
51 let mut heap = BinaryHeap::from(take(&mut self.pending_weights));
52 let (mut current_weight, mut count) = match heap.pop() {
53 Some(Reverse(w)) => (w, 1),
54 None => return,
55 };
56 while let Some(Reverse(weight)) = heap.pop() {
57 if weight == current_weight {
58 count += 1;
59 if count >= 3 {
60 if let Some(w) = current_weight.checked_mul(2) {
61 heap.push(Reverse(w));
62 }
63 count -= 2;
64 }
65 continue;
66 }
67 for _ in 0..count {
68 if self.size == !0 {
69 self.dp.resize(self.dp.len() + current_weight);
70 }
71 self.dp.shl_bitor_assign(current_weight);
72 }
73 (current_weight, count) = (weight, 1);
74 }
75 for _ in 0..count {
76 if self.size == !0 {
77 self.dp.resize(self.dp.len() + current_weight);
78 }
79 self.dp.shl_bitor_assign(current_weight);
80 }
81 }More examples
crates/competitive/src/math/bit_matrix.rs (line 29)
27 pub fn from_vec(data: Vec<BitSet>) -> Self {
28 let shape = (data.len(), data.first().map_or(0, BitSet::len));
29 assert!(data.iter().all(|row| row.len() == shape.1));
30 Self { shape, data }
31 }
32
33 pub fn new_with(shape: (usize, usize), mut f: impl FnMut(usize, usize) -> bool) -> Self {
34 let mut a = Self::zeros(shape);
35 for (i, row) in a.data.iter_mut().enumerate() {
36 for (w, word) in row.words_mut().iter_mut().enumerate() {
37 for j in w * 64..shape.1.min((w + 1) * 64) {
38 *word |= u64::from(f(i, j)) << (j & 63);
39 }
40 }
41 }
42 a
43 }
44
45 pub fn eye(shape: (usize, usize)) -> Self {
46 let mut a = Self::zeros(shape);
47 for i in 0..shape.0.min(shape.1) {
48 a[i].set(i, true);
49 }
50 a
51 }
52
53 pub fn transpose(&self) -> Self {
54 let mut a = Self::zeros((self.shape.1, self.shape.0));
55 for (i, row) in self.data.iter().enumerate() {
56 for j in row.iter_ones() {
57 a[j].set(i, true);
58 }
59 }
60 a
61 }
62
63 /// Replaces the matrix with reduced row echelon form and returns its pivot columns.
64 pub fn row_reduction(&mut self) -> Vec<usize> {
65 self.eliminate(self.shape.1, true, false)
66 }
67
68 /// Replaces the matrix with row echelon form and returns its rank.
69 pub fn rank(&mut self) -> usize {
70 self.eliminate(self.shape.1, false, false).len()
71 }
72
73 /// Computes the determinant in place. The matrix must be square.
74 pub fn determinant(&mut self) -> bool {
75 assert_eq!(self.shape.0, self.shape.1);
76 self.eliminate(self.shape.1, false, true).len() == self.shape.0
77 }
78
79 /// Returns the inverse, or `None` if singular. The matrix must be square.
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }pub fn is_empty(&self) -> bool
Sourcepub fn from_binary(s: &str) -> Option<Self>
pub fn from_binary(s: &str) -> Option<Self>
Parses ASCII 0 and 1, with the first character at bit index zero.
Returns None if any other character occurs.
Examples found in repository?
crates/library_checker/src/linear_algebra/matrix_rank_mod_2.rs (line 29)
5pub fn matrix_rank_mod_2(reader: impl Read, writer: impl Write) {
6 prepare_io!(reader, writer);
7 sc!(n, m);
8 // Transpose very tall matrices to avoid allocating millions of short rows.
9 let transpose = n / 2 > m;
10 let mut a = BitMatrix::zeros(if transpose { (m, n) } else { (n, m) });
11 if transpose && m >= 64 {
12 let mut words = vec![0u64; m];
13 for first in (0..n).step_by(64) {
14 words.fill(0);
15 for i in 0..64.min(n - first) {
16 sc!(row: &str);
17 for (word, b) in words.iter_mut().zip(row.bytes()) {
18 *word |= u64::from(b == b'1') << i;
19 }
20 }
21 for (row, &word) in a.data.iter_mut().zip(&words) {
22 row.words_mut()[first / 64] = word;
23 }
24 }
25 } else {
26 for i in 0..if m == 0 { 0 } else { n } {
27 sc!(row: &str);
28 if !transpose {
29 a.data[i] = BitSet::from_binary(row).unwrap();
30 } else {
31 for (j, b) in row.bytes().enumerate() {
32 a[j].words_mut()[i / 64] |= u64::from(b == b'1') << (i % 64);
33 }
34 }
35 if transpose
36 && i == 63
37 && BitMatrix::new_with((m, 64), |row, col| a[row].get(col)).rank() == m
38 {
39 pp!(m);
40 return;
41 }
42 }
43 }
44 pp!(a.rank());
45}Sourcefn parse_binary_scalar(bytes: &[u8], words: &mut [u64]) -> bool
fn parse_binary_scalar(bytes: &[u8], words: &mut [u64]) -> bool
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 57)
45 pub fn from_binary(s: &str) -> Option<Self> {
46 let bytes = s.as_bytes();
47 let mut bits = Self::new(bytes.len());
48 let end = bytes.len() / 64 * 64;
49 #[cfg(target_arch = "x86_64")]
50 let parsed = if avx512_enabled() && is_x86_feature_detected!("avx512bw") {
51 // SAFETY: AVX-512BW is available; each complete chunk contains 64 bytes.
52 unsafe { simd::parse_binary_avx512(&bytes[..end], bits.words_mut()) }
53 } else if is_x86_feature_detected!("avx2") {
54 // SAFETY: AVX2 is available; each complete chunk contains 64 bytes.
55 unsafe { simd::parse_binary_avx2(&bytes[..end], bits.words_mut()) }
56 } else {
57 Self::parse_binary_scalar(&bytes[..end], bits.words_mut())
58 };
59 #[cfg(not(target_arch = "x86_64"))]
60 let parsed = Self::parse_binary_scalar(&bytes[..end], bits.words_mut());
61 if !parsed {
62 return None;
63 }
64 if end != bytes.len() {
65 let mut word = 0;
66 for (i, &b) in bytes[end..].iter().enumerate() {
67 if b != b'0' && b != b'1' {
68 return None;
69 }
70 word |= u64::from(b & 1) << i;
71 }
72 bits.words_mut()[end / 64] = word;
73 }
74 Some(bits)
75 }Sourcepub fn to_binary(&self) -> String
pub fn to_binary(&self) -> String
Returns ASCII 0 and 1 in increasing bit-index order.
Examples found in repository?
crates/library_checker/src/linear_algebra/inverse_matrix_mod_2.rs (line 11)
5pub fn inverse_matrix_mod_2(reader: impl Read, writer: impl Write) {
6 prepare_io!(reader, writer);
7 sc!(n, a: [@BitSet::from_binary; n]);
8 let a = BitMatrix::from_vec(a);
9 if let Some(b) = a.inverse() {
10 for row in b.data {
11 pp!(row.to_binary());
12 }
13 } else {
14 pp!(-1);
15 }
16}More examples
crates/library_checker/src/linear_algebra/system_of_linear_equations_mod_2.rs (line 12)
5pub fn system_of_linear_equations_mod_2(reader: impl Read, writer: impl Write) {
6 prepare_io!(reader, writer);
7 sc!(n, _m, a: [@BitSet::from_binary; n], b: @BitSet::from_binary);
8 let a = BitMatrix::from_vec(a);
9 if let Some(sol) = a.solve_system_of_linear_equations(&b) {
10 pp!(sol.basis.len());
11 for row in std::iter::once(sol.particular).chain(sol.basis) {
12 pp!(row.to_binary());
13 }
14 } else {
15 pp!(-1);
16 }
17}Sourcepub fn ones(size: usize) -> Self
pub fn ones(size: usize) -> Self
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 117)
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }Sourcepub fn get(&self, i: usize) -> bool
pub fn get(&self, i: usize) -> bool
Examples found in repository?
More examples
crates/competitive/src/algorithm/automata_learning.rs (line 372)
355 pub fn construct_dfa(&mut self) -> DeterministicFiniteAutomaton {
356 let sigma = self.automaton.sigma();
357 let mut dfa = DeterministicFiniteAutomaton {
358 states: vec![],
359 initial_state: 0,
360 };
361 let mut i_prefix = 0;
362 while i_prefix < self.prefixes.len() {
363 let mut delta = vec![];
364 for x in 0..sigma {
365 let prefix: Vec<usize> =
366 self.prefixes[i_prefix].iter().cloned().chain([x]).collect();
367 let index = self.add_prefix(prefix);
368 delta.push(index);
369 }
370 dfa.states.push(DfaState {
371 delta,
372 accept: self.table[i_prefix].get(0),
373 });
374 i_prefix += 1;
375 }
376 dfa
377 }crates/competitive/src/math/bit_matrix.rs (line 110)
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }
138
139 pub fn pow(self, mut n: usize) -> Self {
140 assert_eq!(self.shape.0, self.shape.1);
141 let mut result = Self::eye(self.shape);
142 let mut a = self;
143 while n != 0 {
144 if n & 1 != 0 {
145 result = &result * &a;
146 }
147 n >>= 1;
148 if n != 0 {
149 a = &a * &a;
150 }
151 }
152 result
153 }
154
155 fn eliminate(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
156 #[cfg(target_arch = "x86_64")]
157 match simd_backend() {
158 // SAFETY: the dispatcher checks the required CPU features.
159 SimdBackend::Avx512 => {
160 return unsafe { self.eliminate_avx512(cols, full, require_full_rank) };
161 }
162 // SAFETY: the dispatcher checks AVX2 support.
163 SimdBackend::Avx2 => {
164 return unsafe { self.eliminate_avx2(cols, full, require_full_rank) };
165 }
166 SimdBackend::Scalar => {}
167 }
168 self.eliminate_impl(cols, full, require_full_rank)
169 }
170
171 // Inlined into each target-feature entry point to vectorize the row operations.
172 #[inline(always)]
173 fn eliminate_impl(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
174 let n = self.shape.0;
175 let mut pivots = Vec::with_capacity(n.min(cols));
176 if n < 32 {
177 let mut c = 0;
178 while c < cols {
179 let r = pivots.len();
180 if r == n {
181 break;
182 }
183 let Some(p) = (r..n).find(|&i| self[i].get(c)) else {
184 if require_full_rank {
185 return pivots;
186 }
187 c = self.next_column(r, c + 1, cols);
188 continue;
189 };
190 self.data.swap(r, p);
191 let (upper, lower) = self.data.split_at_mut(r);
192 let (pivot, lower) = lower.split_first_mut().unwrap();
193 for row in lower
194 .iter_mut()
195 .chain(upper.iter_mut().take(if full { r } else { 0 }))
196 {
197 if row.get(c) {
198 xor(&mut row.words_mut()[c / 64..], &pivot.words()[c / 64..]);
199 }
200 }
201 pivots.push(c);
202 c += 1;
203 }
204 return pivots;
205 }
206 // Eliminating a shared leading coefficient preserves the two-coefficient bound.
207 if self
208 .data
209 .iter()
210 .all(|row| row.iter_ones().take_while(|&c| c < cols).take(3).count() <= 2)
211 {
212 return self.eliminate_sparse(cols, full, require_full_rank);
213 }
214 let block: usize = if n < 512 {
215 4
216 } else if n < 1536 {
217 8
218 } else {
219 32
220 };
221 let mut table = vec![BitSet::new(self.shape.1); (1 << block.min(8)) * block.div_ceil(8)];
222 let mut reduced = vec![0; n];
223 let mut start = 0;
224 while start < cols {
225 let first = pivots.len();
226 let word = start / 64;
227 reduced.fill(first);
228 let end = cols.min(start + block);
229 let mut c = start;
230 while c < end {
231 let r = pivots.len();
232 let mut pivot = None;
233 for (i, reduced) in reduced.iter_mut().enumerate().skip(r) {
234 let (upper, lower) = self.data.split_at_mut(i);
235 let row = &mut lower[0];
236 for p in *reduced..r {
237 if row.get(pivots[p]) {
238 xor(&mut row.words_mut()[word..], &upper[p].words()[word..]);
239 }
240 }
241 *reduced = r;
242 if row.get(c) {
243 pivot = Some(i);
244 break;
245 }
246 }
247 if let Some(p) = pivot {
248 self.data.swap(r, p);
249 reduced.swap(r, p);
250 pivots.push(c);
251 c += 1;
252 } else if require_full_rank {
253 return pivots;
254 } else {
255 c = self.next_column(r, c + 1, end);
256 }
257 }
258 let rank = pivots.len();
259 if first == rank {
260 let next = self.next_column(rank, start + block, cols);
261 if next == cols {
262 break;
263 }
264 start = next / block * block;
265 continue;
266 }
267 // Make the panel's pivot columns an identity matrix before indexing its table.
268 for r in (first..rank).rev() {
269 let (upper, lower) = self.data.split_at_mut(r);
270 for row in &mut upper[first..] {
271 if row.get(pivots[r]) {
272 xor(&mut row.words_mut()[word..], &lower[0].words()[word..]);
273 }
274 }
275 }
276 let mut indices = [[0usize; 256]; 4];
277 let mut masks = [0usize; 4];
278 for group in 0..block.div_ceil(8) {
279 let mut keys = [0usize; 256];
280 let mut count = 0;
281 for (row, &c) in pivots[first..].iter().enumerate() {
282 if (c - start) / 8 != group {
283 continue;
284 }
285 let half = 1 << count;
286 count += 1;
287 for index in 0..half {
288 keys[index + half] = keys[index] | (1 << ((c - start) % 8));
289 let (lower, upper) = table.split_at_mut(group * 256 + index + half);
290 let target = &mut upper[0].words_mut()[word..];
291 let source = &lower[group * 256 + index].words()[word..];
292 let pivot = &self[first + row].words()[word..];
293 for ((x, y), z) in target.iter_mut().zip(source).zip(pivot) {
294 *x = y ^ z;
295 }
296 }
297 }
298 masks[group] = keys[(1 << count) - 1];
299 for (i, &key) in keys[..1 << count].iter().enumerate() {
300 indices[group][key] = i;
301 }
302 }
303 for i in (rank..n).chain(0..if full { first } else { 0 }) {
304 let key = (self[i].words()[word] >> (start & 63)) as usize;
305 let x = indices[0][key & masks[0]];
306 if block <= 8 {
307 if x != 0 {
308 xor(&mut self[i].words_mut()[word..], &table[x].words()[word..]);
309 }
310 continue;
311 }
312 let y = indices[1][(key >> 8) & masks[1]];
313 let z = indices[2][(key >> 16) & masks[2]];
314 let w = indices[3][(key >> 24) & masks[3]];
315 if x | y | z | w != 0 {
316 let p = &table[x].words()[word..];
317 let q = &table[256 + y].words()[word..];
318 let r = &table[512 + z].words()[word..];
319 let s = &table[768 + w].words()[word..];
320 for ((((x, y), z), r), s) in self[i].words_mut()[word..]
321 .iter_mut()
322 .zip(p)
323 .zip(q)
324 .zip(r)
325 .zip(s)
326 {
327 *x ^= y ^ z ^ r ^ s;
328 }
329 }
330 }
331 if rank == n {
332 break;
333 }
334 start += block;
335 }
336 pivots
337 }crates/library_checker/src/linear_algebra/matrix_rank_mod_2.rs (line 37)
5pub fn matrix_rank_mod_2(reader: impl Read, writer: impl Write) {
6 prepare_io!(reader, writer);
7 sc!(n, m);
8 // Transpose very tall matrices to avoid allocating millions of short rows.
9 let transpose = n / 2 > m;
10 let mut a = BitMatrix::zeros(if transpose { (m, n) } else { (n, m) });
11 if transpose && m >= 64 {
12 let mut words = vec![0u64; m];
13 for first in (0..n).step_by(64) {
14 words.fill(0);
15 for i in 0..64.min(n - first) {
16 sc!(row: &str);
17 for (word, b) in words.iter_mut().zip(row.bytes()) {
18 *word |= u64::from(b == b'1') << i;
19 }
20 }
21 for (row, &word) in a.data.iter_mut().zip(&words) {
22 row.words_mut()[first / 64] = word;
23 }
24 }
25 } else {
26 for i in 0..if m == 0 { 0 } else { n } {
27 sc!(row: &str);
28 if !transpose {
29 a.data[i] = BitSet::from_binary(row).unwrap();
30 } else {
31 for (j, b) in row.bytes().enumerate() {
32 a[j].words_mut()[i / 64] |= u64::from(b == b'1') << (i % 64);
33 }
34 }
35 if transpose
36 && i == 63
37 && BitMatrix::new_with((m, 64), |row, col| a[row].get(col)).rank() == m
38 {
39 pp!(m);
40 return;
41 }
42 }
43 }
44 pp!(a.rank());
45}Sourcepub fn set(&mut self, i: usize, b: bool)
pub fn set(&mut self, i: usize, b: bool)
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 48)
45 pub fn eye(shape: (usize, usize)) -> Self {
46 let mut a = Self::zeros(shape);
47 for i in 0..shape.0.min(shape.1) {
48 a[i].set(i, true);
49 }
50 a
51 }
52
53 pub fn transpose(&self) -> Self {
54 let mut a = Self::zeros((self.shape.1, self.shape.0));
55 for (i, row) in self.data.iter().enumerate() {
56 for j in row.iter_ones() {
57 a[j].set(i, true);
58 }
59 }
60 a
61 }
62
63 /// Replaces the matrix with reduced row echelon form and returns its pivot columns.
64 pub fn row_reduction(&mut self) -> Vec<usize> {
65 self.eliminate(self.shape.1, true, false)
66 }
67
68 /// Replaces the matrix with row echelon form and returns its rank.
69 pub fn rank(&mut self) -> usize {
70 self.eliminate(self.shape.1, false, false).len()
71 }
72
73 /// Computes the determinant in place. The matrix must be square.
74 pub fn determinant(&mut self) -> bool {
75 assert_eq!(self.shape.0, self.shape.1);
76 self.eliminate(self.shape.1, false, true).len() == self.shape.0
77 }
78
79 /// Returns the inverse, or `None` if singular. The matrix must be square.
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }More examples
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Clears all bits.
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 372)
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }Sourcepub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_
pub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_
Iterates over set-bit indices in ascending order.
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 56)
53 pub fn transpose(&self) -> Self {
54 let mut a = Self::zeros((self.shape.1, self.shape.0));
55 for (i, row) in self.data.iter().enumerate() {
56 for j in row.iter_ones() {
57 a[j].set(i, true);
58 }
59 }
60 a
61 }
62
63 /// Replaces the matrix with reduced row echelon form and returns its pivot columns.
64 pub fn row_reduction(&mut self) -> Vec<usize> {
65 self.eliminate(self.shape.1, true, false)
66 }
67
68 /// Replaces the matrix with row echelon form and returns its rank.
69 pub fn rank(&mut self) -> usize {
70 self.eliminate(self.shape.1, false, false).len()
71 }
72
73 /// Computes the determinant in place. The matrix must be square.
74 pub fn determinant(&mut self) -> bool {
75 assert_eq!(self.shape.0, self.shape.1);
76 self.eliminate(self.shape.1, false, true).len() == self.shape.0
77 }
78
79 /// Returns the inverse, or `None` if singular. The matrix must be square.
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }
138
139 pub fn pow(self, mut n: usize) -> Self {
140 assert_eq!(self.shape.0, self.shape.1);
141 let mut result = Self::eye(self.shape);
142 let mut a = self;
143 while n != 0 {
144 if n & 1 != 0 {
145 result = &result * &a;
146 }
147 n >>= 1;
148 if n != 0 {
149 a = &a * &a;
150 }
151 }
152 result
153 }
154
155 fn eliminate(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
156 #[cfg(target_arch = "x86_64")]
157 match simd_backend() {
158 // SAFETY: the dispatcher checks the required CPU features.
159 SimdBackend::Avx512 => {
160 return unsafe { self.eliminate_avx512(cols, full, require_full_rank) };
161 }
162 // SAFETY: the dispatcher checks AVX2 support.
163 SimdBackend::Avx2 => {
164 return unsafe { self.eliminate_avx2(cols, full, require_full_rank) };
165 }
166 SimdBackend::Scalar => {}
167 }
168 self.eliminate_impl(cols, full, require_full_rank)
169 }
170
171 // Inlined into each target-feature entry point to vectorize the row operations.
172 #[inline(always)]
173 fn eliminate_impl(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
174 let n = self.shape.0;
175 let mut pivots = Vec::with_capacity(n.min(cols));
176 if n < 32 {
177 let mut c = 0;
178 while c < cols {
179 let r = pivots.len();
180 if r == n {
181 break;
182 }
183 let Some(p) = (r..n).find(|&i| self[i].get(c)) else {
184 if require_full_rank {
185 return pivots;
186 }
187 c = self.next_column(r, c + 1, cols);
188 continue;
189 };
190 self.data.swap(r, p);
191 let (upper, lower) = self.data.split_at_mut(r);
192 let (pivot, lower) = lower.split_first_mut().unwrap();
193 for row in lower
194 .iter_mut()
195 .chain(upper.iter_mut().take(if full { r } else { 0 }))
196 {
197 if row.get(c) {
198 xor(&mut row.words_mut()[c / 64..], &pivot.words()[c / 64..]);
199 }
200 }
201 pivots.push(c);
202 c += 1;
203 }
204 return pivots;
205 }
206 // Eliminating a shared leading coefficient preserves the two-coefficient bound.
207 if self
208 .data
209 .iter()
210 .all(|row| row.iter_ones().take_while(|&c| c < cols).take(3).count() <= 2)
211 {
212 return self.eliminate_sparse(cols, full, require_full_rank);
213 }
214 let block: usize = if n < 512 {
215 4
216 } else if n < 1536 {
217 8
218 } else {
219 32
220 };
221 let mut table = vec![BitSet::new(self.shape.1); (1 << block.min(8)) * block.div_ceil(8)];
222 let mut reduced = vec![0; n];
223 let mut start = 0;
224 while start < cols {
225 let first = pivots.len();
226 let word = start / 64;
227 reduced.fill(first);
228 let end = cols.min(start + block);
229 let mut c = start;
230 while c < end {
231 let r = pivots.len();
232 let mut pivot = None;
233 for (i, reduced) in reduced.iter_mut().enumerate().skip(r) {
234 let (upper, lower) = self.data.split_at_mut(i);
235 let row = &mut lower[0];
236 for p in *reduced..r {
237 if row.get(pivots[p]) {
238 xor(&mut row.words_mut()[word..], &upper[p].words()[word..]);
239 }
240 }
241 *reduced = r;
242 if row.get(c) {
243 pivot = Some(i);
244 break;
245 }
246 }
247 if let Some(p) = pivot {
248 self.data.swap(r, p);
249 reduced.swap(r, p);
250 pivots.push(c);
251 c += 1;
252 } else if require_full_rank {
253 return pivots;
254 } else {
255 c = self.next_column(r, c + 1, end);
256 }
257 }
258 let rank = pivots.len();
259 if first == rank {
260 let next = self.next_column(rank, start + block, cols);
261 if next == cols {
262 break;
263 }
264 start = next / block * block;
265 continue;
266 }
267 // Make the panel's pivot columns an identity matrix before indexing its table.
268 for r in (first..rank).rev() {
269 let (upper, lower) = self.data.split_at_mut(r);
270 for row in &mut upper[first..] {
271 if row.get(pivots[r]) {
272 xor(&mut row.words_mut()[word..], &lower[0].words()[word..]);
273 }
274 }
275 }
276 let mut indices = [[0usize; 256]; 4];
277 let mut masks = [0usize; 4];
278 for group in 0..block.div_ceil(8) {
279 let mut keys = [0usize; 256];
280 let mut count = 0;
281 for (row, &c) in pivots[first..].iter().enumerate() {
282 if (c - start) / 8 != group {
283 continue;
284 }
285 let half = 1 << count;
286 count += 1;
287 for index in 0..half {
288 keys[index + half] = keys[index] | (1 << ((c - start) % 8));
289 let (lower, upper) = table.split_at_mut(group * 256 + index + half);
290 let target = &mut upper[0].words_mut()[word..];
291 let source = &lower[group * 256 + index].words()[word..];
292 let pivot = &self[first + row].words()[word..];
293 for ((x, y), z) in target.iter_mut().zip(source).zip(pivot) {
294 *x = y ^ z;
295 }
296 }
297 }
298 masks[group] = keys[(1 << count) - 1];
299 for (i, &key) in keys[..1 << count].iter().enumerate() {
300 indices[group][key] = i;
301 }
302 }
303 for i in (rank..n).chain(0..if full { first } else { 0 }) {
304 let key = (self[i].words()[word] >> (start & 63)) as usize;
305 let x = indices[0][key & masks[0]];
306 if block <= 8 {
307 if x != 0 {
308 xor(&mut self[i].words_mut()[word..], &table[x].words()[word..]);
309 }
310 continue;
311 }
312 let y = indices[1][(key >> 8) & masks[1]];
313 let z = indices[2][(key >> 16) & masks[2]];
314 let w = indices[3][(key >> 24) & masks[3]];
315 if x | y | z | w != 0 {
316 let p = &table[x].words()[word..];
317 let q = &table[256 + y].words()[word..];
318 let r = &table[512 + z].words()[word..];
319 let s = &table[768 + w].words()[word..];
320 for ((((x, y), z), r), s) in self[i].words_mut()[word..]
321 .iter_mut()
322 .zip(p)
323 .zip(q)
324 .zip(r)
325 .zip(s)
326 {
327 *x ^= y ^ z ^ r ^ s;
328 }
329 }
330 }
331 if rank == n {
332 break;
333 }
334 start += block;
335 }
336 pivots
337 }
338
339 fn next_column(&self, row: usize, mut start: usize, cols: usize) -> usize {
340 while start < cols {
341 let word = start / 64;
342 let bits = self.data[row..]
343 .iter()
344 .fold(0, |x, row| x | row.words()[word])
345 & (u64::MAX << (start & 63));
346 if bits != 0 {
347 return (word * 64 + bits.trailing_zeros() as usize).min(cols);
348 }
349 start = (word + 1) * 64;
350 }
351 cols
352 }
353
354 #[inline(always)]
355 fn eliminate_sparse(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
356 let n = self.shape.0;
357 let mut basis = vec![n; cols];
358 let mut pivots = Vec::new();
359 for i in 0..n {
360 loop {
361 let Some(c) = self[i].iter_ones().next().filter(|&c| c < cols) else {
362 if require_full_rank {
363 return pivots;
364 }
365 break;
366 };
367 if basis[c] == n {
368 basis[c] = i;
369 pivots.push(c);
370 break;
371 }
372 let (upper, lower) = self.data.split_at_mut(i);
373 xor(
374 &mut lower[0].words_mut()[c / 64..],
375 &upper[basis[c]].words()[c / 64..],
376 );
377 }
378 }
379 pivots.sort_unstable();
380 self.data
381 .sort_by_cached_key(|row| row.iter_ones().next().filter(|&c| c < cols).unwrap_or(cols));
382 if full {
383 for (i, &c) in pivots.iter().enumerate() {
384 basis[c] = i;
385 }
386 for i in (0..pivots.len()).rev() {
387 let next = self[i].iter_ones().take_while(|&c| c < cols).nth(1);
388 if let Some(c) = next
389 && basis[c] != n
390 {
391 let (upper, lower) = self.data.split_at_mut(basis[c]);
392 xor(
393 &mut upper[i].words_mut()[c / 64..],
394 &lower[0].words()[c / 64..],
395 );
396 }
397 }
398 }
399 pivots
400 }
401
402 #[inline(always)]
403 fn mul_impl(&self, rhs: &Self) -> Self {
404 let mut result = Self::zeros((self.shape.0, rhs.shape.1));
405 let ones = self.data.iter().map(BitSet::count_ones).sum::<u64>();
406 let size = self.shape.0 as u64 * self.shape.1 as u64;
407 if self.shape.0 < 256 || self.shape.1 < 32 || ones <= size / 8 {
408 for (a, c) in self.data.iter().zip(&mut result.data) {
409 for j in a.iter_ones() {
410 xor(c.words_mut(), rhs[j].words());
411 }
412 }
413 return result;
414 }
415 if size - ones <= size / 8 {
416 let mut sum = BitSet::new(rhs.shape.1);
417 for row in &rhs.data {
418 sum ^= row;
419 }
420 for (a, c) in self.data.iter().zip(&mut result.data) {
421 c.words_mut().copy_from_slice(sum.words());
422 for j in (!a.clone()).iter_ones() {
423 xor(c.words_mut(), rhs[j].words());
424 }
425 }
426 return result;
427 }
428 let width = rhs.shape.1.div_ceil(64);
429 if width == 0 {
430 return result;
431 }
432
433 // Separate the table groups by a cache line to avoid mapping them to the same sets.
434 let group = 256 * width + 8;
435 let mut storage = BitSet::new(8 * group * 64);
436 let table = storage.words_mut();
437 for start in (0..self.shape.1).step_by(64) {
438 for (t, table) in table.chunks_exact_mut(group).enumerate() {
439 let col = start + t * 8;
440 for bit in 0..self.shape.1.saturating_sub(col).min(8) {
441 let row = rhs[col + bit].words();
442 let half = (1 << bit) * width;
443 let (lower, upper) = table.split_at_mut(half);
444 for (source, dest) in
445 lower.chunks_exact(width).zip(upper.chunks_exact_mut(width))
446 {
447 for ((x, y), z) in dest.iter_mut().zip(source).zip(row) {
448 *x = y ^ z;
449 }
450 }
451 }
452 }
453 for (a, c) in self.data.iter().zip(&mut result.data) {
454 let key = a.words()[start / 64];
455 let offset = (key & 255) as usize * width;
456 let p0 = &table[offset..offset + width];
457 let offset = group + (key >> 8 & 255) as usize * width;
458 let p1 = &table[offset..offset + width];
459 let offset = 2 * group + (key >> 16 & 255) as usize * width;
460 let p2 = &table[offset..offset + width];
461 let offset = 3 * group + (key >> 24 & 255) as usize * width;
462 let p3 = &table[offset..offset + width];
463 let offset = 4 * group + (key >> 32 & 255) as usize * width;
464 let p4 = &table[offset..offset + width];
465 let offset = 5 * group + (key >> 40 & 255) as usize * width;
466 let p5 = &table[offset..offset + width];
467 let offset = 6 * group + (key >> 48 & 255) as usize * width;
468 let p6 = &table[offset..offset + width];
469 let offset = 7 * group + (key >> 56 & 255) as usize * width;
470 let p7 = &table[offset..offset + width];
471 for ((((((((x, p0), p1), p2), p3), p4), p5), p6), p7) in c
472 .words_mut()
473 .iter_mut()
474 .zip(p0)
475 .zip(p1)
476 .zip(p2)
477 .zip(p3)
478 .zip(p4)
479 .zip(p5)
480 .zip(p6)
481 .zip(p7)
482 {
483 *x ^= p0 ^ p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ p7;
484 }
485 }
486 }
487 result
488 }Sourcepub fn count_zeros(&self) -> u64
pub fn count_zeros(&self) -> u64
Counts unset bits.
Sourcepub fn push(&mut self, b: bool)
pub fn push(&mut self, b: bool)
Examples found in repository?
More examples
crates/competitive/src/algorithm/automata_learning.rs (lines 344-347)
339 fn add_suffix(&mut self, suffix: Vec<usize>) {
340 if self.suffixes.contains(&suffix) {
341 return;
342 }
343 for (prefix, table) in self.prefixes.iter_mut().zip(&mut self.table) {
344 table.push(
345 self.automaton
346 .behavior(prefix.iter().cloned().chain(suffix.iter().cloned())),
347 );
348 }
349 self.suffixes.push(suffix);
350 self.row_map.clear();
351 for (i_prefix, row) in self.table.iter().enumerate() {
352 self.row_map.insert(row.clone(), i_prefix);
353 }
354 }Sourcepub fn resize(&mut self, new_size: usize)
pub fn resize(&mut self, new_size: usize)
Examples found in repository?
crates/competitive/src/combinatorial_optimization/subset_sum_problem.rs (line 69)
47 fn rebuild(&mut self) {
48 if self.pending_weights.is_empty() {
49 return;
50 }
51 let mut heap = BinaryHeap::from(take(&mut self.pending_weights));
52 let (mut current_weight, mut count) = match heap.pop() {
53 Some(Reverse(w)) => (w, 1),
54 None => return,
55 };
56 while let Some(Reverse(weight)) = heap.pop() {
57 if weight == current_weight {
58 count += 1;
59 if count >= 3 {
60 if let Some(w) = current_weight.checked_mul(2) {
61 heap.push(Reverse(w));
62 }
63 count -= 2;
64 }
65 continue;
66 }
67 for _ in 0..count {
68 if self.size == !0 {
69 self.dp.resize(self.dp.len() + current_weight);
70 }
71 self.dp.shl_bitor_assign(current_weight);
72 }
73 (current_weight, count) = (weight, 1);
74 }
75 for _ in 0..count {
76 if self.size == !0 {
77 self.dp.resize(self.dp.len() + current_weight);
78 }
79 self.dp.shl_bitor_assign(current_weight);
80 }
81 }Sourcepub fn shl_bitor_assign(&mut self, rhs: usize)
pub fn shl_bitor_assign(&mut self, rhs: usize)
Assigns self | (self << rhs) to self.
Examples found in repository?
crates/competitive/src/combinatorial_optimization/subset_sum_problem.rs (line 71)
47 fn rebuild(&mut self) {
48 if self.pending_weights.is_empty() {
49 return;
50 }
51 let mut heap = BinaryHeap::from(take(&mut self.pending_weights));
52 let (mut current_weight, mut count) = match heap.pop() {
53 Some(Reverse(w)) => (w, 1),
54 None => return,
55 };
56 while let Some(Reverse(weight)) = heap.pop() {
57 if weight == current_weight {
58 count += 1;
59 if count >= 3 {
60 if let Some(w) = current_weight.checked_mul(2) {
61 heap.push(Reverse(w));
62 }
63 count -= 2;
64 }
65 continue;
66 }
67 for _ in 0..count {
68 if self.size == !0 {
69 self.dp.resize(self.dp.len() + current_weight);
70 }
71 self.dp.shl_bitor_assign(current_weight);
72 }
73 (current_weight, count) = (weight, 1);
74 }
75 for _ in 0..count {
76 if self.size == !0 {
77 self.dp.resize(self.dp.len() + current_weight);
78 }
79 self.dp.shl_bitor_assign(current_weight);
80 }
81 }Sourcepub fn shr_bitor_assign(&mut self, rhs: usize)
pub fn shr_bitor_assign(&mut self, rhs: usize)
Assigns self | (self >> rhs) to self.
Sourcepub fn words(&self) -> &[u64]
pub fn words(&self) -> &[u64]
Returns words in increasing bit-index order; unused high bits in the last word are zero.
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 85)
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }
138
139 pub fn pow(self, mut n: usize) -> Self {
140 assert_eq!(self.shape.0, self.shape.1);
141 let mut result = Self::eye(self.shape);
142 let mut a = self;
143 while n != 0 {
144 if n & 1 != 0 {
145 result = &result * &a;
146 }
147 n >>= 1;
148 if n != 0 {
149 a = &a * &a;
150 }
151 }
152 result
153 }
154
155 fn eliminate(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
156 #[cfg(target_arch = "x86_64")]
157 match simd_backend() {
158 // SAFETY: the dispatcher checks the required CPU features.
159 SimdBackend::Avx512 => {
160 return unsafe { self.eliminate_avx512(cols, full, require_full_rank) };
161 }
162 // SAFETY: the dispatcher checks AVX2 support.
163 SimdBackend::Avx2 => {
164 return unsafe { self.eliminate_avx2(cols, full, require_full_rank) };
165 }
166 SimdBackend::Scalar => {}
167 }
168 self.eliminate_impl(cols, full, require_full_rank)
169 }
170
171 // Inlined into each target-feature entry point to vectorize the row operations.
172 #[inline(always)]
173 fn eliminate_impl(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
174 let n = self.shape.0;
175 let mut pivots = Vec::with_capacity(n.min(cols));
176 if n < 32 {
177 let mut c = 0;
178 while c < cols {
179 let r = pivots.len();
180 if r == n {
181 break;
182 }
183 let Some(p) = (r..n).find(|&i| self[i].get(c)) else {
184 if require_full_rank {
185 return pivots;
186 }
187 c = self.next_column(r, c + 1, cols);
188 continue;
189 };
190 self.data.swap(r, p);
191 let (upper, lower) = self.data.split_at_mut(r);
192 let (pivot, lower) = lower.split_first_mut().unwrap();
193 for row in lower
194 .iter_mut()
195 .chain(upper.iter_mut().take(if full { r } else { 0 }))
196 {
197 if row.get(c) {
198 xor(&mut row.words_mut()[c / 64..], &pivot.words()[c / 64..]);
199 }
200 }
201 pivots.push(c);
202 c += 1;
203 }
204 return pivots;
205 }
206 // Eliminating a shared leading coefficient preserves the two-coefficient bound.
207 if self
208 .data
209 .iter()
210 .all(|row| row.iter_ones().take_while(|&c| c < cols).take(3).count() <= 2)
211 {
212 return self.eliminate_sparse(cols, full, require_full_rank);
213 }
214 let block: usize = if n < 512 {
215 4
216 } else if n < 1536 {
217 8
218 } else {
219 32
220 };
221 let mut table = vec![BitSet::new(self.shape.1); (1 << block.min(8)) * block.div_ceil(8)];
222 let mut reduced = vec![0; n];
223 let mut start = 0;
224 while start < cols {
225 let first = pivots.len();
226 let word = start / 64;
227 reduced.fill(first);
228 let end = cols.min(start + block);
229 let mut c = start;
230 while c < end {
231 let r = pivots.len();
232 let mut pivot = None;
233 for (i, reduced) in reduced.iter_mut().enumerate().skip(r) {
234 let (upper, lower) = self.data.split_at_mut(i);
235 let row = &mut lower[0];
236 for p in *reduced..r {
237 if row.get(pivots[p]) {
238 xor(&mut row.words_mut()[word..], &upper[p].words()[word..]);
239 }
240 }
241 *reduced = r;
242 if row.get(c) {
243 pivot = Some(i);
244 break;
245 }
246 }
247 if let Some(p) = pivot {
248 self.data.swap(r, p);
249 reduced.swap(r, p);
250 pivots.push(c);
251 c += 1;
252 } else if require_full_rank {
253 return pivots;
254 } else {
255 c = self.next_column(r, c + 1, end);
256 }
257 }
258 let rank = pivots.len();
259 if first == rank {
260 let next = self.next_column(rank, start + block, cols);
261 if next == cols {
262 break;
263 }
264 start = next / block * block;
265 continue;
266 }
267 // Make the panel's pivot columns an identity matrix before indexing its table.
268 for r in (first..rank).rev() {
269 let (upper, lower) = self.data.split_at_mut(r);
270 for row in &mut upper[first..] {
271 if row.get(pivots[r]) {
272 xor(&mut row.words_mut()[word..], &lower[0].words()[word..]);
273 }
274 }
275 }
276 let mut indices = [[0usize; 256]; 4];
277 let mut masks = [0usize; 4];
278 for group in 0..block.div_ceil(8) {
279 let mut keys = [0usize; 256];
280 let mut count = 0;
281 for (row, &c) in pivots[first..].iter().enumerate() {
282 if (c - start) / 8 != group {
283 continue;
284 }
285 let half = 1 << count;
286 count += 1;
287 for index in 0..half {
288 keys[index + half] = keys[index] | (1 << ((c - start) % 8));
289 let (lower, upper) = table.split_at_mut(group * 256 + index + half);
290 let target = &mut upper[0].words_mut()[word..];
291 let source = &lower[group * 256 + index].words()[word..];
292 let pivot = &self[first + row].words()[word..];
293 for ((x, y), z) in target.iter_mut().zip(source).zip(pivot) {
294 *x = y ^ z;
295 }
296 }
297 }
298 masks[group] = keys[(1 << count) - 1];
299 for (i, &key) in keys[..1 << count].iter().enumerate() {
300 indices[group][key] = i;
301 }
302 }
303 for i in (rank..n).chain(0..if full { first } else { 0 }) {
304 let key = (self[i].words()[word] >> (start & 63)) as usize;
305 let x = indices[0][key & masks[0]];
306 if block <= 8 {
307 if x != 0 {
308 xor(&mut self[i].words_mut()[word..], &table[x].words()[word..]);
309 }
310 continue;
311 }
312 let y = indices[1][(key >> 8) & masks[1]];
313 let z = indices[2][(key >> 16) & masks[2]];
314 let w = indices[3][(key >> 24) & masks[3]];
315 if x | y | z | w != 0 {
316 let p = &table[x].words()[word..];
317 let q = &table[256 + y].words()[word..];
318 let r = &table[512 + z].words()[word..];
319 let s = &table[768 + w].words()[word..];
320 for ((((x, y), z), r), s) in self[i].words_mut()[word..]
321 .iter_mut()
322 .zip(p)
323 .zip(q)
324 .zip(r)
325 .zip(s)
326 {
327 *x ^= y ^ z ^ r ^ s;
328 }
329 }
330 }
331 if rank == n {
332 break;
333 }
334 start += block;
335 }
336 pivots
337 }
338
339 fn next_column(&self, row: usize, mut start: usize, cols: usize) -> usize {
340 while start < cols {
341 let word = start / 64;
342 let bits = self.data[row..]
343 .iter()
344 .fold(0, |x, row| x | row.words()[word])
345 & (u64::MAX << (start & 63));
346 if bits != 0 {
347 return (word * 64 + bits.trailing_zeros() as usize).min(cols);
348 }
349 start = (word + 1) * 64;
350 }
351 cols
352 }
353
354 #[inline(always)]
355 fn eliminate_sparse(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
356 let n = self.shape.0;
357 let mut basis = vec![n; cols];
358 let mut pivots = Vec::new();
359 for i in 0..n {
360 loop {
361 let Some(c) = self[i].iter_ones().next().filter(|&c| c < cols) else {
362 if require_full_rank {
363 return pivots;
364 }
365 break;
366 };
367 if basis[c] == n {
368 basis[c] = i;
369 pivots.push(c);
370 break;
371 }
372 let (upper, lower) = self.data.split_at_mut(i);
373 xor(
374 &mut lower[0].words_mut()[c / 64..],
375 &upper[basis[c]].words()[c / 64..],
376 );
377 }
378 }
379 pivots.sort_unstable();
380 self.data
381 .sort_by_cached_key(|row| row.iter_ones().next().filter(|&c| c < cols).unwrap_or(cols));
382 if full {
383 for (i, &c) in pivots.iter().enumerate() {
384 basis[c] = i;
385 }
386 for i in (0..pivots.len()).rev() {
387 let next = self[i].iter_ones().take_while(|&c| c < cols).nth(1);
388 if let Some(c) = next
389 && basis[c] != n
390 {
391 let (upper, lower) = self.data.split_at_mut(basis[c]);
392 xor(
393 &mut upper[i].words_mut()[c / 64..],
394 &lower[0].words()[c / 64..],
395 );
396 }
397 }
398 }
399 pivots
400 }
401
402 #[inline(always)]
403 fn mul_impl(&self, rhs: &Self) -> Self {
404 let mut result = Self::zeros((self.shape.0, rhs.shape.1));
405 let ones = self.data.iter().map(BitSet::count_ones).sum::<u64>();
406 let size = self.shape.0 as u64 * self.shape.1 as u64;
407 if self.shape.0 < 256 || self.shape.1 < 32 || ones <= size / 8 {
408 for (a, c) in self.data.iter().zip(&mut result.data) {
409 for j in a.iter_ones() {
410 xor(c.words_mut(), rhs[j].words());
411 }
412 }
413 return result;
414 }
415 if size - ones <= size / 8 {
416 let mut sum = BitSet::new(rhs.shape.1);
417 for row in &rhs.data {
418 sum ^= row;
419 }
420 for (a, c) in self.data.iter().zip(&mut result.data) {
421 c.words_mut().copy_from_slice(sum.words());
422 for j in (!a.clone()).iter_ones() {
423 xor(c.words_mut(), rhs[j].words());
424 }
425 }
426 return result;
427 }
428 let width = rhs.shape.1.div_ceil(64);
429 if width == 0 {
430 return result;
431 }
432
433 // Separate the table groups by a cache line to avoid mapping them to the same sets.
434 let group = 256 * width + 8;
435 let mut storage = BitSet::new(8 * group * 64);
436 let table = storage.words_mut();
437 for start in (0..self.shape.1).step_by(64) {
438 for (t, table) in table.chunks_exact_mut(group).enumerate() {
439 let col = start + t * 8;
440 for bit in 0..self.shape.1.saturating_sub(col).min(8) {
441 let row = rhs[col + bit].words();
442 let half = (1 << bit) * width;
443 let (lower, upper) = table.split_at_mut(half);
444 for (source, dest) in
445 lower.chunks_exact(width).zip(upper.chunks_exact_mut(width))
446 {
447 for ((x, y), z) in dest.iter_mut().zip(source).zip(row) {
448 *x = y ^ z;
449 }
450 }
451 }
452 }
453 for (a, c) in self.data.iter().zip(&mut result.data) {
454 let key = a.words()[start / 64];
455 let offset = (key & 255) as usize * width;
456 let p0 = &table[offset..offset + width];
457 let offset = group + (key >> 8 & 255) as usize * width;
458 let p1 = &table[offset..offset + width];
459 let offset = 2 * group + (key >> 16 & 255) as usize * width;
460 let p2 = &table[offset..offset + width];
461 let offset = 3 * group + (key >> 24 & 255) as usize * width;
462 let p3 = &table[offset..offset + width];
463 let offset = 4 * group + (key >> 32 & 255) as usize * width;
464 let p4 = &table[offset..offset + width];
465 let offset = 5 * group + (key >> 40 & 255) as usize * width;
466 let p5 = &table[offset..offset + width];
467 let offset = 6 * group + (key >> 48 & 255) as usize * width;
468 let p6 = &table[offset..offset + width];
469 let offset = 7 * group + (key >> 56 & 255) as usize * width;
470 let p7 = &table[offset..offset + width];
471 for ((((((((x, p0), p1), p2), p3), p4), p5), p6), p7) in c
472 .words_mut()
473 .iter_mut()
474 .zip(p0)
475 .zip(p1)
476 .zip(p2)
477 .zip(p3)
478 .zip(p4)
479 .zip(p5)
480 .zip(p6)
481 .zip(p7)
482 {
483 *x ^= p0 ^ p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ p7;
484 }
485 }
486 }
487 result
488 }More examples
crates/competitive/src/data_structure/bitset.rs (line 112)
92 pub fn to_binary(&self) -> String {
93 const TABLE: [[u8; 8]; 256] = {
94 let mut table = [[b'0'; 8]; 256];
95 let mut i = 0;
96 while i < 256 {
97 let mut j = 0;
98 while j < 8 {
99 table[i][j] |= ((i >> j) & 1) as u8;
100 j += 1;
101 }
102 i += 1;
103 }
104 table
105 };
106 let mut bytes = vec![b'0'; self.size.div_ceil(8) * 8];
107 #[cfg(target_arch = "x86_64")]
108 let end = if self.size >= 64 && avx512_enabled() && is_x86_feature_detected!("avx512bw") {
109 let end = self.size / 64 * 64;
110 // SAFETY: AVX-512BW is available; each output chunk holds one 64-bit word.
111 unsafe {
112 simd::write_binary_avx512(&mut bytes[..end], self.words());
113 }
114 end
115 } else if self.size >= 64 && is_x86_feature_detected!("avx2") {
116 let end = self.size / 64 * 64;
117 // SAFETY: AVX2 is available; each output chunk holds one complete 64-bit word.
118 unsafe {
119 simd::write_binary_avx2(&mut bytes[..end], self.words());
120 }
121 end
122 } else {
123 0
124 };
125 #[cfg(not(target_arch = "x86_64"))]
126 let end = 0;
127 for (chunk, &word) in bytes[end..].chunks_mut(64).zip(&self.words()[end / 64..]) {
128 for (i, byte) in chunk.as_chunks_mut::<8>().0.iter_mut().enumerate() {
129 byte.copy_from_slice(&TABLE[(word >> (i * 8) & 255) as usize]);
130 }
131 }
132 bytes.truncate(self.size);
133 // SAFETY: every output byte is ASCII `0` or `1`.
134 unsafe { String::from_utf8_unchecked(bytes) }
135 }
136
137 pub fn ones(size: usize) -> Self {
138 let mut self_ = Self {
139 size,
140 bits: vec![Block([u64::MAX; 8]); size.div_ceil(512)],
141 };
142 self_.trim();
143 self_
144 }
145
146 pub fn get(&self, i: usize) -> bool {
147 self.bits[i >> 9].0[i >> 6 & 7] & (1 << (i & 63)) != 0
148 }
149
150 pub fn set(&mut self, i: usize, b: bool) {
151 let word = &mut self.bits[i >> 9].0[i >> 6 & 7];
152 if b {
153 *word |= 1 << (i & 63);
154 } else {
155 *word &= !(1 << (i & 63));
156 }
157 }
158
159 /// Clears all bits.
160 pub fn reset(&mut self) {
161 self.bits.fill(Block::default());
162 }
163
164 /// Sets all bits to `value`.
165 pub fn fill(&mut self, value: bool) {
166 self.bits.fill(Block([if value { u64::MAX } else { 0 }; 8]));
167 self.trim();
168 }
169
170 /// Tests whether any bit is set.
171 #[inline]
172 pub fn any(&self) -> bool {
173 !self.none()
174 }
175
176 /// Tests whether all bits are unset.
177 #[inline]
178 pub fn none(&self) -> bool {
179 #[cfg(target_arch = "x86_64")]
180 if self.bits.len() >= SIMD_MIN_BLOCKS {
181 if self.bits[0].0[0] != 0 {
182 return false;
183 }
184 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
185 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
186 return unsafe { simd::none_avx512(&self.bits) };
187 }
188 if is_x86_feature_detected!("avx2") {
189 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
190 return unsafe { simd::none_avx2(&self.bits) };
191 }
192 }
193 self.words().iter().all(|&word| word == 0)
194 }
195
196 /// Tests whether all bits are set.
197 #[inline(always)]
198 pub fn all(&self) -> bool {
199 let words = self.words();
200 let full_words = self.size >> 6;
201 #[cfg(target_arch = "x86_64")]
202 if self.size >> 9 >= SIMD_MIN_BLOCKS {
203 let full_blocks = self.size >> 9;
204 if words[0] != u64::MAX {
205 return false;
206 }
207 let full_blocks_are_set = if avx512_enabled() && is_x86_feature_detected!("avx512f") {
208 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
209 Some(unsafe { simd::all_avx512(&self.bits[..full_blocks]) })
210 } else if is_x86_feature_detected!("avx2") {
211 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
212 Some(unsafe { simd::all_avx2(&self.bits[..full_blocks]) })
213 } else {
214 None
215 };
216 if let Some(full_blocks_are_set) = full_blocks_are_set {
217 return full_blocks_are_set
218 && words[full_blocks * 8..full_words]
219 .iter()
220 .all(|&word| word == u64::MAX)
221 && (self.size & 63 == 0
222 || words[full_words] == u64::MAX >> (64 - (self.size & 63)));
223 }
224 }
225 if self.size & 63 == 0 {
226 return words.iter().all(|&word| word == u64::MAX);
227 }
228 words[..full_words].iter().all(|&word| word == u64::MAX)
229 && words[full_words] == u64::MAX >> (64 - (self.size & 63))
230 }
231
232 /// Iterates over set-bit indices in ascending order.
233 pub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_ {
234 self.words()
235 .iter()
236 .copied()
237 .enumerate()
238 .flat_map(|(word_index, mut word)| {
239 std::iter::from_fn(move || {
240 if word == 0 {
241 None
242 } else {
243 let bit = word.trailing_zeros() as usize;
244 word &= word - 1;
245 Some((word_index << 6) | bit)
246 }
247 })
248 })
249 }
250
251 /// Counts set bits.
252 #[inline]
253 pub fn count_ones(&self) -> u64 {
254 let words = self.words();
255 #[cfg(target_arch = "x86_64")]
256 if words.len() >= 8 {
257 if avx512_enabled()
258 && is_x86_feature_detected!("avx512f")
259 && is_x86_feature_detected!("avx512vpopcntdq")
260 {
261 // SAFETY: blocks are aligned and feature detection checked both requirements.
262 return unsafe { simd::count_ones_avx512(&self.bits) };
263 }
264 if is_x86_feature_detected!("avx2") {
265 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
266 return unsafe { simd::count_ones_avx2(&self.bits) };
267 }
268 }
269 words.iter().map(|word| word.count_ones() as u64).sum()
270 }
271
272 /// Counts unset bits.
273 #[inline]
274 pub fn count_zeros(&self) -> u64 {
275 self.size as u64 - self.count_ones()
276 }
277
278 pub fn push(&mut self, b: bool) {
279 if self.size & 511 == 0 {
280 self.bits.push(Block::default());
281 }
282 if b {
283 self.bits[self.size >> 9].0[self.size >> 6 & 7] |= 1 << (self.size & 63);
284 }
285 self.size += 1;
286 }
287
288 pub fn resize(&mut self, new_size: usize) {
289 match self.size.cmp(&new_size) {
290 Ordering::Less => self.bits.resize(new_size.div_ceil(512), Block::default()),
291 Ordering::Equal => {}
292 Ordering::Greater => self.bits.truncate(new_size.div_ceil(512)),
293 }
294 self.size = new_size;
295 self.trim();
296 }
297
298 /// Assigns `self | (self << rhs)` to `self`.
299 #[inline]
300 pub fn shl_bitor_assign(&mut self, rhs: usize) {
301 self.shift_left::<true>(rhs);
302 }
303
304 /// Assigns `self | (self >> rhs)` to `self`.
305 #[inline]
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }Sourcepub fn words_mut(&mut self) -> &mut [u64]
pub fn words_mut(&mut self) -> &mut [u64]
Returns mutable words in increasing bit-index order. Callers must keep unused high bits in the last word zero.
Examples found in repository?
crates/competitive/src/math/bit_matrix.rs (line 36)
33 pub fn new_with(shape: (usize, usize), mut f: impl FnMut(usize, usize) -> bool) -> Self {
34 let mut a = Self::zeros(shape);
35 for (i, row) in a.data.iter_mut().enumerate() {
36 for (w, word) in row.words_mut().iter_mut().enumerate() {
37 for j in w * 64..shape.1.min((w + 1) * 64) {
38 *word |= u64::from(f(i, j)) << (j & 63);
39 }
40 }
41 }
42 a
43 }
44
45 pub fn eye(shape: (usize, usize)) -> Self {
46 let mut a = Self::zeros(shape);
47 for i in 0..shape.0.min(shape.1) {
48 a[i].set(i, true);
49 }
50 a
51 }
52
53 pub fn transpose(&self) -> Self {
54 let mut a = Self::zeros((self.shape.1, self.shape.0));
55 for (i, row) in self.data.iter().enumerate() {
56 for j in row.iter_ones() {
57 a[j].set(i, true);
58 }
59 }
60 a
61 }
62
63 /// Replaces the matrix with reduced row echelon form and returns its pivot columns.
64 pub fn row_reduction(&mut self) -> Vec<usize> {
65 self.eliminate(self.shape.1, true, false)
66 }
67
68 /// Replaces the matrix with row echelon form and returns its rank.
69 pub fn rank(&mut self) -> usize {
70 self.eliminate(self.shape.1, false, false).len()
71 }
72
73 /// Computes the determinant in place. The matrix must be square.
74 pub fn determinant(&mut self) -> bool {
75 assert_eq!(self.shape.0, self.shape.1);
76 self.eliminate(self.shape.1, false, true).len() == self.shape.0
77 }
78
79 /// Returns the inverse, or `None` if singular. The matrix must be square.
80 pub fn inverse(&self) -> Option<Self> {
81 let (n, m) = self.shape;
82 assert_eq!(n, m);
83 let mut a = Self::zeros((n, 2 * n));
84 for i in 0..n {
85 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
86 a[i].set(n + i, true);
87 }
88 if a.eliminate(n, true, true).len() != n {
89 return None;
90 }
91 for row in &mut a.data {
92 *row >>= n;
93 }
94 let mut inverse = Self::zeros((n, n));
95 for (row, source) in inverse.data.iter_mut().zip(&a.data) {
96 let len = row.words().len();
97 row.words_mut().copy_from_slice(&source.words()[..len]);
98 }
99 Some(inverse)
100 }
101
102 /// Returns a particular solution and a basis of the kernel, or `None` if inconsistent.
103 /// `b.len()` must equal the number of rows.
104 pub fn solve_system_of_linear_equations(&self, b: &BitSet) -> Option<BitMatrixSolution> {
105 let (n, m) = self.shape;
106 assert_eq!(b.len(), n);
107 let mut a = Self::zeros((n, m + 1));
108 for i in 0..n {
109 a[i].words_mut()[..self[i].words().len()].copy_from_slice(self[i].words());
110 a[i].set(m, b.get(i));
111 }
112 let pivots = a.eliminate(m, true, false);
113 if a.data[pivots.len()..].iter().any(|row| row.get(m)) {
114 return None;
115 }
116 let mut particular = BitSet::new(m);
117 let mut free = BitSet::ones(m);
118 for (i, &c) in pivots.iter().enumerate() {
119 particular.set(c, a[i].get(m));
120 free.set(c, false);
121 }
122 let columns: Vec<_> = free.iter_ones().collect();
123 let mut basis: Vec<_> = columns
124 .iter()
125 .map(|&c| {
126 let mut row = BitSet::new(m);
127 row.set(c, true);
128 row
129 })
130 .collect();
131 for (i, &p) in pivots.iter().enumerate() {
132 for (row, &c) in basis.iter_mut().zip(&columns) {
133 row.words_mut()[p / 64] |= u64::from(a[i].get(c)) << (p & 63);
134 }
135 }
136 Some(BitMatrixSolution { particular, basis })
137 }
138
139 pub fn pow(self, mut n: usize) -> Self {
140 assert_eq!(self.shape.0, self.shape.1);
141 let mut result = Self::eye(self.shape);
142 let mut a = self;
143 while n != 0 {
144 if n & 1 != 0 {
145 result = &result * &a;
146 }
147 n >>= 1;
148 if n != 0 {
149 a = &a * &a;
150 }
151 }
152 result
153 }
154
155 fn eliminate(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
156 #[cfg(target_arch = "x86_64")]
157 match simd_backend() {
158 // SAFETY: the dispatcher checks the required CPU features.
159 SimdBackend::Avx512 => {
160 return unsafe { self.eliminate_avx512(cols, full, require_full_rank) };
161 }
162 // SAFETY: the dispatcher checks AVX2 support.
163 SimdBackend::Avx2 => {
164 return unsafe { self.eliminate_avx2(cols, full, require_full_rank) };
165 }
166 SimdBackend::Scalar => {}
167 }
168 self.eliminate_impl(cols, full, require_full_rank)
169 }
170
171 // Inlined into each target-feature entry point to vectorize the row operations.
172 #[inline(always)]
173 fn eliminate_impl(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
174 let n = self.shape.0;
175 let mut pivots = Vec::with_capacity(n.min(cols));
176 if n < 32 {
177 let mut c = 0;
178 while c < cols {
179 let r = pivots.len();
180 if r == n {
181 break;
182 }
183 let Some(p) = (r..n).find(|&i| self[i].get(c)) else {
184 if require_full_rank {
185 return pivots;
186 }
187 c = self.next_column(r, c + 1, cols);
188 continue;
189 };
190 self.data.swap(r, p);
191 let (upper, lower) = self.data.split_at_mut(r);
192 let (pivot, lower) = lower.split_first_mut().unwrap();
193 for row in lower
194 .iter_mut()
195 .chain(upper.iter_mut().take(if full { r } else { 0 }))
196 {
197 if row.get(c) {
198 xor(&mut row.words_mut()[c / 64..], &pivot.words()[c / 64..]);
199 }
200 }
201 pivots.push(c);
202 c += 1;
203 }
204 return pivots;
205 }
206 // Eliminating a shared leading coefficient preserves the two-coefficient bound.
207 if self
208 .data
209 .iter()
210 .all(|row| row.iter_ones().take_while(|&c| c < cols).take(3).count() <= 2)
211 {
212 return self.eliminate_sparse(cols, full, require_full_rank);
213 }
214 let block: usize = if n < 512 {
215 4
216 } else if n < 1536 {
217 8
218 } else {
219 32
220 };
221 let mut table = vec![BitSet::new(self.shape.1); (1 << block.min(8)) * block.div_ceil(8)];
222 let mut reduced = vec![0; n];
223 let mut start = 0;
224 while start < cols {
225 let first = pivots.len();
226 let word = start / 64;
227 reduced.fill(first);
228 let end = cols.min(start + block);
229 let mut c = start;
230 while c < end {
231 let r = pivots.len();
232 let mut pivot = None;
233 for (i, reduced) in reduced.iter_mut().enumerate().skip(r) {
234 let (upper, lower) = self.data.split_at_mut(i);
235 let row = &mut lower[0];
236 for p in *reduced..r {
237 if row.get(pivots[p]) {
238 xor(&mut row.words_mut()[word..], &upper[p].words()[word..]);
239 }
240 }
241 *reduced = r;
242 if row.get(c) {
243 pivot = Some(i);
244 break;
245 }
246 }
247 if let Some(p) = pivot {
248 self.data.swap(r, p);
249 reduced.swap(r, p);
250 pivots.push(c);
251 c += 1;
252 } else if require_full_rank {
253 return pivots;
254 } else {
255 c = self.next_column(r, c + 1, end);
256 }
257 }
258 let rank = pivots.len();
259 if first == rank {
260 let next = self.next_column(rank, start + block, cols);
261 if next == cols {
262 break;
263 }
264 start = next / block * block;
265 continue;
266 }
267 // Make the panel's pivot columns an identity matrix before indexing its table.
268 for r in (first..rank).rev() {
269 let (upper, lower) = self.data.split_at_mut(r);
270 for row in &mut upper[first..] {
271 if row.get(pivots[r]) {
272 xor(&mut row.words_mut()[word..], &lower[0].words()[word..]);
273 }
274 }
275 }
276 let mut indices = [[0usize; 256]; 4];
277 let mut masks = [0usize; 4];
278 for group in 0..block.div_ceil(8) {
279 let mut keys = [0usize; 256];
280 let mut count = 0;
281 for (row, &c) in pivots[first..].iter().enumerate() {
282 if (c - start) / 8 != group {
283 continue;
284 }
285 let half = 1 << count;
286 count += 1;
287 for index in 0..half {
288 keys[index + half] = keys[index] | (1 << ((c - start) % 8));
289 let (lower, upper) = table.split_at_mut(group * 256 + index + half);
290 let target = &mut upper[0].words_mut()[word..];
291 let source = &lower[group * 256 + index].words()[word..];
292 let pivot = &self[first + row].words()[word..];
293 for ((x, y), z) in target.iter_mut().zip(source).zip(pivot) {
294 *x = y ^ z;
295 }
296 }
297 }
298 masks[group] = keys[(1 << count) - 1];
299 for (i, &key) in keys[..1 << count].iter().enumerate() {
300 indices[group][key] = i;
301 }
302 }
303 for i in (rank..n).chain(0..if full { first } else { 0 }) {
304 let key = (self[i].words()[word] >> (start & 63)) as usize;
305 let x = indices[0][key & masks[0]];
306 if block <= 8 {
307 if x != 0 {
308 xor(&mut self[i].words_mut()[word..], &table[x].words()[word..]);
309 }
310 continue;
311 }
312 let y = indices[1][(key >> 8) & masks[1]];
313 let z = indices[2][(key >> 16) & masks[2]];
314 let w = indices[3][(key >> 24) & masks[3]];
315 if x | y | z | w != 0 {
316 let p = &table[x].words()[word..];
317 let q = &table[256 + y].words()[word..];
318 let r = &table[512 + z].words()[word..];
319 let s = &table[768 + w].words()[word..];
320 for ((((x, y), z), r), s) in self[i].words_mut()[word..]
321 .iter_mut()
322 .zip(p)
323 .zip(q)
324 .zip(r)
325 .zip(s)
326 {
327 *x ^= y ^ z ^ r ^ s;
328 }
329 }
330 }
331 if rank == n {
332 break;
333 }
334 start += block;
335 }
336 pivots
337 }
338
339 fn next_column(&self, row: usize, mut start: usize, cols: usize) -> usize {
340 while start < cols {
341 let word = start / 64;
342 let bits = self.data[row..]
343 .iter()
344 .fold(0, |x, row| x | row.words()[word])
345 & (u64::MAX << (start & 63));
346 if bits != 0 {
347 return (word * 64 + bits.trailing_zeros() as usize).min(cols);
348 }
349 start = (word + 1) * 64;
350 }
351 cols
352 }
353
354 #[inline(always)]
355 fn eliminate_sparse(&mut self, cols: usize, full: bool, require_full_rank: bool) -> Vec<usize> {
356 let n = self.shape.0;
357 let mut basis = vec![n; cols];
358 let mut pivots = Vec::new();
359 for i in 0..n {
360 loop {
361 let Some(c) = self[i].iter_ones().next().filter(|&c| c < cols) else {
362 if require_full_rank {
363 return pivots;
364 }
365 break;
366 };
367 if basis[c] == n {
368 basis[c] = i;
369 pivots.push(c);
370 break;
371 }
372 let (upper, lower) = self.data.split_at_mut(i);
373 xor(
374 &mut lower[0].words_mut()[c / 64..],
375 &upper[basis[c]].words()[c / 64..],
376 );
377 }
378 }
379 pivots.sort_unstable();
380 self.data
381 .sort_by_cached_key(|row| row.iter_ones().next().filter(|&c| c < cols).unwrap_or(cols));
382 if full {
383 for (i, &c) in pivots.iter().enumerate() {
384 basis[c] = i;
385 }
386 for i in (0..pivots.len()).rev() {
387 let next = self[i].iter_ones().take_while(|&c| c < cols).nth(1);
388 if let Some(c) = next
389 && basis[c] != n
390 {
391 let (upper, lower) = self.data.split_at_mut(basis[c]);
392 xor(
393 &mut upper[i].words_mut()[c / 64..],
394 &lower[0].words()[c / 64..],
395 );
396 }
397 }
398 }
399 pivots
400 }
401
402 #[inline(always)]
403 fn mul_impl(&self, rhs: &Self) -> Self {
404 let mut result = Self::zeros((self.shape.0, rhs.shape.1));
405 let ones = self.data.iter().map(BitSet::count_ones).sum::<u64>();
406 let size = self.shape.0 as u64 * self.shape.1 as u64;
407 if self.shape.0 < 256 || self.shape.1 < 32 || ones <= size / 8 {
408 for (a, c) in self.data.iter().zip(&mut result.data) {
409 for j in a.iter_ones() {
410 xor(c.words_mut(), rhs[j].words());
411 }
412 }
413 return result;
414 }
415 if size - ones <= size / 8 {
416 let mut sum = BitSet::new(rhs.shape.1);
417 for row in &rhs.data {
418 sum ^= row;
419 }
420 for (a, c) in self.data.iter().zip(&mut result.data) {
421 c.words_mut().copy_from_slice(sum.words());
422 for j in (!a.clone()).iter_ones() {
423 xor(c.words_mut(), rhs[j].words());
424 }
425 }
426 return result;
427 }
428 let width = rhs.shape.1.div_ceil(64);
429 if width == 0 {
430 return result;
431 }
432
433 // Separate the table groups by a cache line to avoid mapping them to the same sets.
434 let group = 256 * width + 8;
435 let mut storage = BitSet::new(8 * group * 64);
436 let table = storage.words_mut();
437 for start in (0..self.shape.1).step_by(64) {
438 for (t, table) in table.chunks_exact_mut(group).enumerate() {
439 let col = start + t * 8;
440 for bit in 0..self.shape.1.saturating_sub(col).min(8) {
441 let row = rhs[col + bit].words();
442 let half = (1 << bit) * width;
443 let (lower, upper) = table.split_at_mut(half);
444 for (source, dest) in
445 lower.chunks_exact(width).zip(upper.chunks_exact_mut(width))
446 {
447 for ((x, y), z) in dest.iter_mut().zip(source).zip(row) {
448 *x = y ^ z;
449 }
450 }
451 }
452 }
453 for (a, c) in self.data.iter().zip(&mut result.data) {
454 let key = a.words()[start / 64];
455 let offset = (key & 255) as usize * width;
456 let p0 = &table[offset..offset + width];
457 let offset = group + (key >> 8 & 255) as usize * width;
458 let p1 = &table[offset..offset + width];
459 let offset = 2 * group + (key >> 16 & 255) as usize * width;
460 let p2 = &table[offset..offset + width];
461 let offset = 3 * group + (key >> 24 & 255) as usize * width;
462 let p3 = &table[offset..offset + width];
463 let offset = 4 * group + (key >> 32 & 255) as usize * width;
464 let p4 = &table[offset..offset + width];
465 let offset = 5 * group + (key >> 40 & 255) as usize * width;
466 let p5 = &table[offset..offset + width];
467 let offset = 6 * group + (key >> 48 & 255) as usize * width;
468 let p6 = &table[offset..offset + width];
469 let offset = 7 * group + (key >> 56 & 255) as usize * width;
470 let p7 = &table[offset..offset + width];
471 for ((((((((x, p0), p1), p2), p3), p4), p5), p6), p7) in c
472 .words_mut()
473 .iter_mut()
474 .zip(p0)
475 .zip(p1)
476 .zip(p2)
477 .zip(p3)
478 .zip(p4)
479 .zip(p5)
480 .zip(p6)
481 .zip(p7)
482 {
483 *x ^= p0 ^ p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ p7;
484 }
485 }
486 }
487 result
488 }More examples
crates/competitive/src/data_structure/bitset.rs (line 52)
45 pub fn from_binary(s: &str) -> Option<Self> {
46 let bytes = s.as_bytes();
47 let mut bits = Self::new(bytes.len());
48 let end = bytes.len() / 64 * 64;
49 #[cfg(target_arch = "x86_64")]
50 let parsed = if avx512_enabled() && is_x86_feature_detected!("avx512bw") {
51 // SAFETY: AVX-512BW is available; each complete chunk contains 64 bytes.
52 unsafe { simd::parse_binary_avx512(&bytes[..end], bits.words_mut()) }
53 } else if is_x86_feature_detected!("avx2") {
54 // SAFETY: AVX2 is available; each complete chunk contains 64 bytes.
55 unsafe { simd::parse_binary_avx2(&bytes[..end], bits.words_mut()) }
56 } else {
57 Self::parse_binary_scalar(&bytes[..end], bits.words_mut())
58 };
59 #[cfg(not(target_arch = "x86_64"))]
60 let parsed = Self::parse_binary_scalar(&bytes[..end], bits.words_mut());
61 if !parsed {
62 return None;
63 }
64 if end != bytes.len() {
65 let mut word = 0;
66 for (i, &b) in bytes[end..].iter().enumerate() {
67 if b != b'0' && b != b'1' {
68 return None;
69 }
70 word |= u64::from(b & 1) << i;
71 }
72 bits.words_mut()[end / 64] = word;
73 }
74 Some(bits)
75 }
76
77 fn parse_binary_scalar(bytes: &[u8], words: &mut [u64]) -> bool {
78 for (chunk, word) in bytes.as_chunks::<64>().0.iter().zip(words) {
79 for (i, byte) in chunk.as_chunks::<8>().0.iter().enumerate() {
80 let x = u64::from_le_bytes(*byte);
81 if x & 0xfefe_fefe_fefe_fefe != 0x3030_3030_3030_3030 {
82 return false;
83 }
84 *word |= ((x & 0x0101_0101_0101_0101).wrapping_mul(0x0102_0408_1020_4080) >> 56)
85 << (i * 8);
86 }
87 }
88 true
89 }
90
91 /// Returns ASCII `0` and `1` in increasing bit-index order.
92 pub fn to_binary(&self) -> String {
93 const TABLE: [[u8; 8]; 256] = {
94 let mut table = [[b'0'; 8]; 256];
95 let mut i = 0;
96 while i < 256 {
97 let mut j = 0;
98 while j < 8 {
99 table[i][j] |= ((i >> j) & 1) as u8;
100 j += 1;
101 }
102 i += 1;
103 }
104 table
105 };
106 let mut bytes = vec![b'0'; self.size.div_ceil(8) * 8];
107 #[cfg(target_arch = "x86_64")]
108 let end = if self.size >= 64 && avx512_enabled() && is_x86_feature_detected!("avx512bw") {
109 let end = self.size / 64 * 64;
110 // SAFETY: AVX-512BW is available; each output chunk holds one 64-bit word.
111 unsafe {
112 simd::write_binary_avx512(&mut bytes[..end], self.words());
113 }
114 end
115 } else if self.size >= 64 && is_x86_feature_detected!("avx2") {
116 let end = self.size / 64 * 64;
117 // SAFETY: AVX2 is available; each output chunk holds one complete 64-bit word.
118 unsafe {
119 simd::write_binary_avx2(&mut bytes[..end], self.words());
120 }
121 end
122 } else {
123 0
124 };
125 #[cfg(not(target_arch = "x86_64"))]
126 let end = 0;
127 for (chunk, &word) in bytes[end..].chunks_mut(64).zip(&self.words()[end / 64..]) {
128 for (i, byte) in chunk.as_chunks_mut::<8>().0.iter_mut().enumerate() {
129 byte.copy_from_slice(&TABLE[(word >> (i * 8) & 255) as usize]);
130 }
131 }
132 bytes.truncate(self.size);
133 // SAFETY: every output byte is ASCII `0` or `1`.
134 unsafe { String::from_utf8_unchecked(bytes) }
135 }
136
137 pub fn ones(size: usize) -> Self {
138 let mut self_ = Self {
139 size,
140 bits: vec![Block([u64::MAX; 8]); size.div_ceil(512)],
141 };
142 self_.trim();
143 self_
144 }
145
146 pub fn get(&self, i: usize) -> bool {
147 self.bits[i >> 9].0[i >> 6 & 7] & (1 << (i & 63)) != 0
148 }
149
150 pub fn set(&mut self, i: usize, b: bool) {
151 let word = &mut self.bits[i >> 9].0[i >> 6 & 7];
152 if b {
153 *word |= 1 << (i & 63);
154 } else {
155 *word &= !(1 << (i & 63));
156 }
157 }
158
159 /// Clears all bits.
160 pub fn reset(&mut self) {
161 self.bits.fill(Block::default());
162 }
163
164 /// Sets all bits to `value`.
165 pub fn fill(&mut self, value: bool) {
166 self.bits.fill(Block([if value { u64::MAX } else { 0 }; 8]));
167 self.trim();
168 }
169
170 /// Tests whether any bit is set.
171 #[inline]
172 pub fn any(&self) -> bool {
173 !self.none()
174 }
175
176 /// Tests whether all bits are unset.
177 #[inline]
178 pub fn none(&self) -> bool {
179 #[cfg(target_arch = "x86_64")]
180 if self.bits.len() >= SIMD_MIN_BLOCKS {
181 if self.bits[0].0[0] != 0 {
182 return false;
183 }
184 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
185 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
186 return unsafe { simd::none_avx512(&self.bits) };
187 }
188 if is_x86_feature_detected!("avx2") {
189 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
190 return unsafe { simd::none_avx2(&self.bits) };
191 }
192 }
193 self.words().iter().all(|&word| word == 0)
194 }
195
196 /// Tests whether all bits are set.
197 #[inline(always)]
198 pub fn all(&self) -> bool {
199 let words = self.words();
200 let full_words = self.size >> 6;
201 #[cfg(target_arch = "x86_64")]
202 if self.size >> 9 >= SIMD_MIN_BLOCKS {
203 let full_blocks = self.size >> 9;
204 if words[0] != u64::MAX {
205 return false;
206 }
207 let full_blocks_are_set = if avx512_enabled() && is_x86_feature_detected!("avx512f") {
208 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
209 Some(unsafe { simd::all_avx512(&self.bits[..full_blocks]) })
210 } else if is_x86_feature_detected!("avx2") {
211 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
212 Some(unsafe { simd::all_avx2(&self.bits[..full_blocks]) })
213 } else {
214 None
215 };
216 if let Some(full_blocks_are_set) = full_blocks_are_set {
217 return full_blocks_are_set
218 && words[full_blocks * 8..full_words]
219 .iter()
220 .all(|&word| word == u64::MAX)
221 && (self.size & 63 == 0
222 || words[full_words] == u64::MAX >> (64 - (self.size & 63)));
223 }
224 }
225 if self.size & 63 == 0 {
226 return words.iter().all(|&word| word == u64::MAX);
227 }
228 words[..full_words].iter().all(|&word| word == u64::MAX)
229 && words[full_words] == u64::MAX >> (64 - (self.size & 63))
230 }
231
232 /// Iterates over set-bit indices in ascending order.
233 pub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_ {
234 self.words()
235 .iter()
236 .copied()
237 .enumerate()
238 .flat_map(|(word_index, mut word)| {
239 std::iter::from_fn(move || {
240 if word == 0 {
241 None
242 } else {
243 let bit = word.trailing_zeros() as usize;
244 word &= word - 1;
245 Some((word_index << 6) | bit)
246 }
247 })
248 })
249 }
250
251 /// Counts set bits.
252 #[inline]
253 pub fn count_ones(&self) -> u64 {
254 let words = self.words();
255 #[cfg(target_arch = "x86_64")]
256 if words.len() >= 8 {
257 if avx512_enabled()
258 && is_x86_feature_detected!("avx512f")
259 && is_x86_feature_detected!("avx512vpopcntdq")
260 {
261 // SAFETY: blocks are aligned and feature detection checked both requirements.
262 return unsafe { simd::count_ones_avx512(&self.bits) };
263 }
264 if is_x86_feature_detected!("avx2") {
265 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
266 return unsafe { simd::count_ones_avx2(&self.bits) };
267 }
268 }
269 words.iter().map(|word| word.count_ones() as u64).sum()
270 }
271
272 /// Counts unset bits.
273 #[inline]
274 pub fn count_zeros(&self) -> u64 {
275 self.size as u64 - self.count_ones()
276 }
277
278 pub fn push(&mut self, b: bool) {
279 if self.size & 511 == 0 {
280 self.bits.push(Block::default());
281 }
282 if b {
283 self.bits[self.size >> 9].0[self.size >> 6 & 7] |= 1 << (self.size & 63);
284 }
285 self.size += 1;
286 }
287
288 pub fn resize(&mut self, new_size: usize) {
289 match self.size.cmp(&new_size) {
290 Ordering::Less => self.bits.resize(new_size.div_ceil(512), Block::default()),
291 Ordering::Equal => {}
292 Ordering::Greater => self.bits.truncate(new_size.div_ceil(512)),
293 }
294 self.size = new_size;
295 self.trim();
296 }
297
298 /// Assigns `self | (self << rhs)` to `self`.
299 #[inline]
300 pub fn shl_bitor_assign(&mut self, rhs: usize) {
301 self.shift_left::<true>(rhs);
302 }
303
304 /// Assigns `self | (self >> rhs)` to `self`.
305 #[inline]
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }
364
365 #[inline]
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }
492}
493
494impl Extend<bool> for BitSet {
495 fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T) {
496 for bit in iter {
497 self.push(bit);
498 }
499 }
500}
501
502impl FromIterator<bool> for BitSet {
503 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
504 let mut set = BitSet::new(0);
505 set.extend(iter);
506 set
507 }
508}
509
510impl ShlAssign<usize> for BitSet {
511 #[inline]
512 fn shl_assign(&mut self, rhs: usize) {
513 self.shift_left::<false>(rhs);
514 }
515}
516
517impl Shl<usize> for BitSet {
518 type Output = Self;
519 fn shl(mut self, rhs: usize) -> Self::Output {
520 self <<= rhs;
521 self
522 }
523}
524
525impl ShrAssign<usize> for BitSet {
526 #[inline]
527 fn shr_assign(&mut self, rhs: usize) {
528 self.shift_right::<false>(rhs);
529 }
530}
531
532impl Shr<usize> for BitSet {
533 type Output = Self;
534 fn shr(mut self, rhs: usize) -> Self::Output {
535 self >>= rhs;
536 self
537 }
538}
539
540impl BitOrAssign<&BitSet> for BitSet {
541 #[inline]
542 fn bitor_assign(&mut self, rhs: &Self) {
543 self.bitop_assign::<BIT_OR>(rhs);
544 }
545}
546
547impl BitOr<&BitSet> for BitSet {
548 type Output = Self;
549 fn bitor(mut self, rhs: &Self) -> Self::Output {
550 self |= rhs;
551 self
552 }
553}
554
555impl BitOr<&BitSet> for &BitSet {
556 type Output = BitSet;
557 fn bitor(self, rhs: &BitSet) -> Self::Output {
558 let mut res = self.clone();
559 res |= rhs;
560 res
561 }
562}
563
564impl BitAndAssign<&BitSet> for BitSet {
565 #[inline]
566 fn bitand_assign(&mut self, rhs: &Self) {
567 self.bitop_assign::<BIT_AND>(rhs);
568 }
569}
570
571impl BitAnd<&BitSet> for BitSet {
572 type Output = Self;
573 fn bitand(mut self, rhs: &Self) -> Self::Output {
574 self &= rhs;
575 self
576 }
577}
578
579impl BitAnd<&BitSet> for &BitSet {
580 type Output = BitSet;
581 fn bitand(self, rhs: &BitSet) -> Self::Output {
582 let mut res = self.clone();
583 res &= rhs;
584 res
585 }
586}
587
588impl BitXorAssign<&BitSet> for BitSet {
589 #[inline]
590 fn bitxor_assign(&mut self, rhs: &Self) {
591 self.bitop_assign::<BIT_XOR>(rhs);
592 }
593}
594
595impl BitXor<&BitSet> for BitSet {
596 type Output = Self;
597 fn bitxor(mut self, rhs: &Self) -> Self::Output {
598 self ^= rhs;
599 self
600 }
601}
602
603impl BitXor<&BitSet> for &BitSet {
604 type Output = BitSet;
605 fn bitxor(self, rhs: &BitSet) -> Self::Output {
606 let mut res = self.clone();
607 res ^= rhs;
608 res
609 }
610}
611
612impl Not for BitSet {
613 type Output = Self;
614 fn not(mut self) -> Self::Output {
615 for word in self.words_mut() {
616 *word = !*word;
617 }
618 self.trim();
619 self
620 }crates/library_checker/src/linear_algebra/matrix_rank_mod_2.rs (line 22)
5pub fn matrix_rank_mod_2(reader: impl Read, writer: impl Write) {
6 prepare_io!(reader, writer);
7 sc!(n, m);
8 // Transpose very tall matrices to avoid allocating millions of short rows.
9 let transpose = n / 2 > m;
10 let mut a = BitMatrix::zeros(if transpose { (m, n) } else { (n, m) });
11 if transpose && m >= 64 {
12 let mut words = vec![0u64; m];
13 for first in (0..n).step_by(64) {
14 words.fill(0);
15 for i in 0..64.min(n - first) {
16 sc!(row: &str);
17 for (word, b) in words.iter_mut().zip(row.bytes()) {
18 *word |= u64::from(b == b'1') << i;
19 }
20 }
21 for (row, &word) in a.data.iter_mut().zip(&words) {
22 row.words_mut()[first / 64] = word;
23 }
24 }
25 } else {
26 for i in 0..if m == 0 { 0 } else { n } {
27 sc!(row: &str);
28 if !transpose {
29 a.data[i] = BitSet::from_binary(row).unwrap();
30 } else {
31 for (j, b) in row.bytes().enumerate() {
32 a[j].words_mut()[i / 64] |= u64::from(b == b'1') << (i % 64);
33 }
34 }
35 if transpose
36 && i == 63
37 && BitMatrix::new_with((m, 64), |row, col| a[row].get(col)).rank() == m
38 {
39 pp!(m);
40 return;
41 }
42 }
43 }
44 pp!(a.rank());
45}Sourcefn trim(&mut self)
fn trim(&mut self)
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 142)
137 pub fn ones(size: usize) -> Self {
138 let mut self_ = Self {
139 size,
140 bits: vec![Block([u64::MAX; 8]); size.div_ceil(512)],
141 };
142 self_.trim();
143 self_
144 }
145
146 pub fn get(&self, i: usize) -> bool {
147 self.bits[i >> 9].0[i >> 6 & 7] & (1 << (i & 63)) != 0
148 }
149
150 pub fn set(&mut self, i: usize, b: bool) {
151 let word = &mut self.bits[i >> 9].0[i >> 6 & 7];
152 if b {
153 *word |= 1 << (i & 63);
154 } else {
155 *word &= !(1 << (i & 63));
156 }
157 }
158
159 /// Clears all bits.
160 pub fn reset(&mut self) {
161 self.bits.fill(Block::default());
162 }
163
164 /// Sets all bits to `value`.
165 pub fn fill(&mut self, value: bool) {
166 self.bits.fill(Block([if value { u64::MAX } else { 0 }; 8]));
167 self.trim();
168 }
169
170 /// Tests whether any bit is set.
171 #[inline]
172 pub fn any(&self) -> bool {
173 !self.none()
174 }
175
176 /// Tests whether all bits are unset.
177 #[inline]
178 pub fn none(&self) -> bool {
179 #[cfg(target_arch = "x86_64")]
180 if self.bits.len() >= SIMD_MIN_BLOCKS {
181 if self.bits[0].0[0] != 0 {
182 return false;
183 }
184 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
185 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
186 return unsafe { simd::none_avx512(&self.bits) };
187 }
188 if is_x86_feature_detected!("avx2") {
189 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
190 return unsafe { simd::none_avx2(&self.bits) };
191 }
192 }
193 self.words().iter().all(|&word| word == 0)
194 }
195
196 /// Tests whether all bits are set.
197 #[inline(always)]
198 pub fn all(&self) -> bool {
199 let words = self.words();
200 let full_words = self.size >> 6;
201 #[cfg(target_arch = "x86_64")]
202 if self.size >> 9 >= SIMD_MIN_BLOCKS {
203 let full_blocks = self.size >> 9;
204 if words[0] != u64::MAX {
205 return false;
206 }
207 let full_blocks_are_set = if avx512_enabled() && is_x86_feature_detected!("avx512f") {
208 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
209 Some(unsafe { simd::all_avx512(&self.bits[..full_blocks]) })
210 } else if is_x86_feature_detected!("avx2") {
211 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
212 Some(unsafe { simd::all_avx2(&self.bits[..full_blocks]) })
213 } else {
214 None
215 };
216 if let Some(full_blocks_are_set) = full_blocks_are_set {
217 return full_blocks_are_set
218 && words[full_blocks * 8..full_words]
219 .iter()
220 .all(|&word| word == u64::MAX)
221 && (self.size & 63 == 0
222 || words[full_words] == u64::MAX >> (64 - (self.size & 63)));
223 }
224 }
225 if self.size & 63 == 0 {
226 return words.iter().all(|&word| word == u64::MAX);
227 }
228 words[..full_words].iter().all(|&word| word == u64::MAX)
229 && words[full_words] == u64::MAX >> (64 - (self.size & 63))
230 }
231
232 /// Iterates over set-bit indices in ascending order.
233 pub fn iter_ones(&self) -> impl Iterator<Item = usize> + '_ {
234 self.words()
235 .iter()
236 .copied()
237 .enumerate()
238 .flat_map(|(word_index, mut word)| {
239 std::iter::from_fn(move || {
240 if word == 0 {
241 None
242 } else {
243 let bit = word.trailing_zeros() as usize;
244 word &= word - 1;
245 Some((word_index << 6) | bit)
246 }
247 })
248 })
249 }
250
251 /// Counts set bits.
252 #[inline]
253 pub fn count_ones(&self) -> u64 {
254 let words = self.words();
255 #[cfg(target_arch = "x86_64")]
256 if words.len() >= 8 {
257 if avx512_enabled()
258 && is_x86_feature_detected!("avx512f")
259 && is_x86_feature_detected!("avx512vpopcntdq")
260 {
261 // SAFETY: blocks are aligned and feature detection checked both requirements.
262 return unsafe { simd::count_ones_avx512(&self.bits) };
263 }
264 if is_x86_feature_detected!("avx2") {
265 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
266 return unsafe { simd::count_ones_avx2(&self.bits) };
267 }
268 }
269 words.iter().map(|word| word.count_ones() as u64).sum()
270 }
271
272 /// Counts unset bits.
273 #[inline]
274 pub fn count_zeros(&self) -> u64 {
275 self.size as u64 - self.count_ones()
276 }
277
278 pub fn push(&mut self, b: bool) {
279 if self.size & 511 == 0 {
280 self.bits.push(Block::default());
281 }
282 if b {
283 self.bits[self.size >> 9].0[self.size >> 6 & 7] |= 1 << (self.size & 63);
284 }
285 self.size += 1;
286 }
287
288 pub fn resize(&mut self, new_size: usize) {
289 match self.size.cmp(&new_size) {
290 Ordering::Less => self.bits.resize(new_size.div_ceil(512), Block::default()),
291 Ordering::Equal => {}
292 Ordering::Greater => self.bits.truncate(new_size.div_ceil(512)),
293 }
294 self.size = new_size;
295 self.trim();
296 }
297
298 /// Assigns `self | (self << rhs)` to `self`.
299 #[inline]
300 pub fn shl_bitor_assign(&mut self, rhs: usize) {
301 self.shift_left::<true>(rhs);
302 }
303
304 /// Assigns `self | (self >> rhs)` to `self`.
305 #[inline]
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }
364
365 #[inline]
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }
492}
493
494impl Extend<bool> for BitSet {
495 fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T) {
496 for bit in iter {
497 self.push(bit);
498 }
499 }
500}
501
502impl FromIterator<bool> for BitSet {
503 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
504 let mut set = BitSet::new(0);
505 set.extend(iter);
506 set
507 }
508}
509
510impl ShlAssign<usize> for BitSet {
511 #[inline]
512 fn shl_assign(&mut self, rhs: usize) {
513 self.shift_left::<false>(rhs);
514 }
515}
516
517impl Shl<usize> for BitSet {
518 type Output = Self;
519 fn shl(mut self, rhs: usize) -> Self::Output {
520 self <<= rhs;
521 self
522 }
523}
524
525impl ShrAssign<usize> for BitSet {
526 #[inline]
527 fn shr_assign(&mut self, rhs: usize) {
528 self.shift_right::<false>(rhs);
529 }
530}
531
532impl Shr<usize> for BitSet {
533 type Output = Self;
534 fn shr(mut self, rhs: usize) -> Self::Output {
535 self >>= rhs;
536 self
537 }
538}
539
540impl BitOrAssign<&BitSet> for BitSet {
541 #[inline]
542 fn bitor_assign(&mut self, rhs: &Self) {
543 self.bitop_assign::<BIT_OR>(rhs);
544 }
545}
546
547impl BitOr<&BitSet> for BitSet {
548 type Output = Self;
549 fn bitor(mut self, rhs: &Self) -> Self::Output {
550 self |= rhs;
551 self
552 }
553}
554
555impl BitOr<&BitSet> for &BitSet {
556 type Output = BitSet;
557 fn bitor(self, rhs: &BitSet) -> Self::Output {
558 let mut res = self.clone();
559 res |= rhs;
560 res
561 }
562}
563
564impl BitAndAssign<&BitSet> for BitSet {
565 #[inline]
566 fn bitand_assign(&mut self, rhs: &Self) {
567 self.bitop_assign::<BIT_AND>(rhs);
568 }
569}
570
571impl BitAnd<&BitSet> for BitSet {
572 type Output = Self;
573 fn bitand(mut self, rhs: &Self) -> Self::Output {
574 self &= rhs;
575 self
576 }
577}
578
579impl BitAnd<&BitSet> for &BitSet {
580 type Output = BitSet;
581 fn bitand(self, rhs: &BitSet) -> Self::Output {
582 let mut res = self.clone();
583 res &= rhs;
584 res
585 }
586}
587
588impl BitXorAssign<&BitSet> for BitSet {
589 #[inline]
590 fn bitxor_assign(&mut self, rhs: &Self) {
591 self.bitop_assign::<BIT_XOR>(rhs);
592 }
593}
594
595impl BitXor<&BitSet> for BitSet {
596 type Output = Self;
597 fn bitxor(mut self, rhs: &Self) -> Self::Output {
598 self ^= rhs;
599 self
600 }
601}
602
603impl BitXor<&BitSet> for &BitSet {
604 type Output = BitSet;
605 fn bitxor(self, rhs: &BitSet) -> Self::Output {
606 let mut res = self.clone();
607 res ^= rhs;
608 res
609 }
610}
611
612impl Not for BitSet {
613 type Output = Self;
614 fn not(mut self) -> Self::Output {
615 for word in self.words_mut() {
616 *word = !*word;
617 }
618 self.trim();
619 self
620 }Sourcefn bitop_assign<const OP: u8>(&mut self, rhs: &Self)
fn bitop_assign<const OP: u8>(&mut self, rhs: &Self)
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 543)
542 fn bitor_assign(&mut self, rhs: &Self) {
543 self.bitop_assign::<BIT_OR>(rhs);
544 }
545}
546
547impl BitOr<&BitSet> for BitSet {
548 type Output = Self;
549 fn bitor(mut self, rhs: &Self) -> Self::Output {
550 self |= rhs;
551 self
552 }
553}
554
555impl BitOr<&BitSet> for &BitSet {
556 type Output = BitSet;
557 fn bitor(self, rhs: &BitSet) -> Self::Output {
558 let mut res = self.clone();
559 res |= rhs;
560 res
561 }
562}
563
564impl BitAndAssign<&BitSet> for BitSet {
565 #[inline]
566 fn bitand_assign(&mut self, rhs: &Self) {
567 self.bitop_assign::<BIT_AND>(rhs);
568 }
569}
570
571impl BitAnd<&BitSet> for BitSet {
572 type Output = Self;
573 fn bitand(mut self, rhs: &Self) -> Self::Output {
574 self &= rhs;
575 self
576 }
577}
578
579impl BitAnd<&BitSet> for &BitSet {
580 type Output = BitSet;
581 fn bitand(self, rhs: &BitSet) -> Self::Output {
582 let mut res = self.clone();
583 res &= rhs;
584 res
585 }
586}
587
588impl BitXorAssign<&BitSet> for BitSet {
589 #[inline]
590 fn bitxor_assign(&mut self, rhs: &Self) {
591 self.bitop_assign::<BIT_XOR>(rhs);
592 }Sourcefn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize)
fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize)
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 301)
300 pub fn shl_bitor_assign(&mut self, rhs: usize) {
301 self.shift_left::<true>(rhs);
302 }
303
304 /// Assigns `self | (self >> rhs)` to `self`.
305 #[inline]
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }
364
365 #[inline]
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }
492}
493
494impl Extend<bool> for BitSet {
495 fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T) {
496 for bit in iter {
497 self.push(bit);
498 }
499 }
500}
501
502impl FromIterator<bool> for BitSet {
503 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
504 let mut set = BitSet::new(0);
505 set.extend(iter);
506 set
507 }
508}
509
510impl ShlAssign<usize> for BitSet {
511 #[inline]
512 fn shl_assign(&mut self, rhs: usize) {
513 self.shift_left::<false>(rhs);
514 }Sourcefn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize)
fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize)
Examples found in repository?
crates/competitive/src/data_structure/bitset.rs (line 307)
306 pub fn shr_bitor_assign(&mut self, rhs: usize) {
307 self.shift_right::<true>(rhs);
308 }
309
310 /// Returns words in increasing bit-index order; unused high bits in the last word are zero.
311 pub fn words(&self) -> &[u64] {
312 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
313 unsafe { std::slice::from_raw_parts(self.bits.as_ptr().cast(), self.size.div_ceil(64)) }
314 }
315
316 /// Returns mutable words in increasing bit-index order.
317 /// Callers must keep unused high bits in the last word zero.
318 pub fn words_mut(&mut self) -> &mut [u64] {
319 let len = self.size.div_ceil(64);
320 // SAFETY: `Block` is exactly eight contiguous `u64`s, with no trailing padding.
321 unsafe { std::slice::from_raw_parts_mut(self.bits.as_mut_ptr().cast(), len) }
322 }
323
324 fn trim(&mut self) {
325 let used_words = self.size.div_ceil(64) & 7;
326 if let Some(last) = self.bits.last_mut() {
327 if self.size & 63 != 0 {
328 last.0[(self.size >> 6) & 7] &= u64::MAX >> (64 - (self.size & 63));
329 }
330 if used_words != 0 {
331 last.0[used_words..].fill(0);
332 }
333 }
334 }
335
336 #[inline]
337 fn bitop_assign<const OP: u8>(&mut self, rhs: &Self) {
338 assert_eq!(
339 self.size, rhs.size,
340 "bitwise operations require equal lengths"
341 );
342 #[cfg(target_arch = "x86_64")]
343 if self.bits.len() >= SIMD_MIN_BLOCKS {
344 if avx512_enabled() && is_x86_feature_detected!("avx512f") {
345 // SAFETY: blocks are 64-byte aligned and feature detection checked AVX-512F.
346 unsafe { simd::bitop_avx512::<OP>(&mut self.bits, &rhs.bits) };
347 return;
348 }
349 if is_x86_feature_detected!("avx2") {
350 // SAFETY: 64-byte alignment also satisfies AVX2 and feature detection checked it.
351 unsafe { simd::bitop_avx2::<OP>(&mut self.bits, &rhs.bits) };
352 return;
353 }
354 }
355 for (lhs, &rhs) in self.words_mut().iter_mut().zip(rhs.words()) {
356 *lhs = match OP {
357 BIT_AND => *lhs & rhs,
358 BIT_OR => *lhs | rhs,
359 BIT_XOR => *lhs ^ rhs,
360 _ => unreachable!(),
361 };
362 }
363 }
364
365 #[inline]
366 fn shift_left<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
367 if rhs == 0 {
368 return;
369 }
370 if rhs >= self.size {
371 if !OR_ASSIGN {
372 self.reset();
373 }
374 return;
375 }
376 #[cfg(target_arch = "x86_64")]
377 if self.bits.len() >= SIMD_MIN_BLOCKS {
378 if avx512_enabled()
379 && is_x86_feature_detected!("avx512f")
380 && is_x86_feature_detected!("avx512vbmi2")
381 {
382 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
383 unsafe { simd::shift_left_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
384 if self.size & 511 != 0 {
385 self.trim();
386 }
387 return;
388 }
389 if is_x86_feature_detected!("avx2") {
390 // SAFETY: feature detection checked AVX2 support.
391 unsafe { simd::shift_left_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
392 if self.size & 63 != 0 {
393 self.trim();
394 }
395 return;
396 }
397 }
398
399 let bits = self.words_mut();
400 let word_shift = rhs >> 6;
401 let bit_shift = rhs & 63;
402 if bit_shift == 0 {
403 for i in (0..bits.len() - word_shift).rev() {
404 if OR_ASSIGN {
405 bits[i + word_shift] |= bits[i];
406 } else {
407 bits[i + word_shift] = bits[i];
408 }
409 }
410 } else {
411 for i in (1..bits.len() - word_shift).rev() {
412 let value = (bits[i] << bit_shift) | (bits[i - 1] >> (64 - bit_shift));
413 if OR_ASSIGN {
414 bits[i + word_shift] |= value;
415 } else {
416 bits[i + word_shift] = value;
417 }
418 }
419 if OR_ASSIGN {
420 bits[word_shift] |= bits[0] << bit_shift;
421 } else {
422 bits[word_shift] = bits[0] << bit_shift;
423 }
424 }
425 if !OR_ASSIGN {
426 bits[..word_shift].fill(0);
427 }
428 if self.size & 63 != 0 {
429 self.trim();
430 }
431 }
432
433 #[inline]
434 fn shift_right<const OR_ASSIGN: bool>(&mut self, rhs: usize) {
435 if rhs == 0 {
436 return;
437 }
438 if rhs >= self.size {
439 if !OR_ASSIGN {
440 self.reset();
441 }
442 return;
443 }
444 #[cfg(target_arch = "x86_64")]
445 if self.bits.len() >= SIMD_MIN_BLOCKS {
446 if avx512_enabled()
447 && is_x86_feature_detected!("avx512f")
448 && is_x86_feature_detected!("avx512vbmi2")
449 {
450 // SAFETY: blocks are aligned and feature detection checked AVX-512F and VBMI2.
451 unsafe { simd::shift_right_avx512::<OR_ASSIGN>(&mut self.bits, rhs) };
452 return;
453 }
454 if is_x86_feature_detected!("avx2") {
455 // SAFETY: feature detection checked AVX2 support.
456 unsafe { simd::shift_right_avx2::<OR_ASSIGN>(self.words_mut(), rhs) };
457 return;
458 }
459 }
460
461 let bits = self.words_mut();
462 let word_shift = rhs >> 6;
463 let bit_shift = rhs & 63;
464 if bit_shift == 0 {
465 for i in word_shift..bits.len() {
466 if OR_ASSIGN {
467 bits[i - word_shift] |= bits[i];
468 } else {
469 bits[i - word_shift] = bits[i];
470 }
471 }
472 } else {
473 for i in word_shift..bits.len() - 1 {
474 let value = (bits[i] >> bit_shift) | (bits[i + 1] << (64 - bit_shift));
475 if OR_ASSIGN {
476 bits[i - word_shift] |= value;
477 } else {
478 bits[i - word_shift] = value;
479 }
480 }
481 if OR_ASSIGN {
482 bits[bits.len() - word_shift - 1] |= bits[bits.len() - 1] >> bit_shift;
483 } else {
484 bits[bits.len() - word_shift - 1] = bits[bits.len() - 1] >> bit_shift;
485 }
486 }
487 if !OR_ASSIGN {
488 let end = bits.len() - word_shift;
489 bits[end..].fill(0);
490 }
491 }
492}
493
494impl Extend<bool> for BitSet {
495 fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T) {
496 for bit in iter {
497 self.push(bit);
498 }
499 }
500}
501
502impl FromIterator<bool> for BitSet {
503 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
504 let mut set = BitSet::new(0);
505 set.extend(iter);
506 set
507 }
508}
509
510impl ShlAssign<usize> for BitSet {
511 #[inline]
512 fn shl_assign(&mut self, rhs: usize) {
513 self.shift_left::<false>(rhs);
514 }
515}
516
517impl Shl<usize> for BitSet {
518 type Output = Self;
519 fn shl(mut self, rhs: usize) -> Self::Output {
520 self <<= rhs;
521 self
522 }
523}
524
525impl ShrAssign<usize> for BitSet {
526 #[inline]
527 fn shr_assign(&mut self, rhs: usize) {
528 self.shift_right::<false>(rhs);
529 }Trait Implementations§
Source§impl BitAndAssign<&BitSet> for BitSet
impl BitAndAssign<&BitSet> for BitSet
Source§fn bitand_assign(&mut self, rhs: &Self)
fn bitand_assign(&mut self, rhs: &Self)
Performs the
&= operation. Read moreSource§impl BitOrAssign<&BitSet> for BitSet
impl BitOrAssign<&BitSet> for BitSet
Source§fn bitor_assign(&mut self, rhs: &Self)
fn bitor_assign(&mut self, rhs: &Self)
Performs the
|= operation. Read moreSource§impl BitXorAssign<&BitSet> for BitSet
impl BitXorAssign<&BitSet> for BitSet
Source§fn bitxor_assign(&mut self, rhs: &Self)
fn bitxor_assign(&mut self, rhs: &Self)
Performs the
^= operation. Read moreimpl Eq for BitSet
Source§impl Extend<bool> for BitSet
impl Extend<bool> for BitSet
Source§fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T)
fn extend<T: IntoIterator<Item = bool>>(&mut self, iter: T)
Extends a collection with the contents of an iterator. Read more
Source§fn extend_one(&mut self, item: T)
fn extend_one(&mut self, item: T)
🔬This is a nightly-only experimental API. (
extend_one)Extends a collection with exactly one element.
Source§fn extend_reserve(&mut self, additional: usize)
fn extend_reserve(&mut self, additional: usize)
🔬This is a nightly-only experimental API. (
extend_one)Reserves capacity in a collection for the given number of additional elements. Read more
Source§impl FromIterator<bool> for BitSet
impl FromIterator<bool> for BitSet
Source§impl Ord for BitSet
impl Ord for BitSet
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Compares and returns the minimum of two values. Read more
Source§impl PartialOrd for BitSet
impl PartialOrd for BitSet
Source§impl ShlAssign<usize> for BitSet
impl ShlAssign<usize> for BitSet
Source§fn shl_assign(&mut self, rhs: usize)
fn shl_assign(&mut self, rhs: usize)
Performs the
<<= operation. Read moreSource§impl ShrAssign<usize> for BitSet
impl ShrAssign<usize> for BitSet
Source§fn shr_assign(&mut self, rhs: usize)
fn shr_assign(&mut self, rhs: usize)
Performs the
>>= operation. Read moreimpl StructuralPartialEq for BitSet
Auto Trait Implementations§
impl Freeze for BitSet
impl RefUnwindSafe for BitSet
impl Send for BitSet
impl Sync for BitSet
impl Unpin for BitSet
impl UnsafeUnpin for BitSet
impl UnwindSafe for BitSet
Blanket Implementations§
Source§impl<T> AsTotalOrd for Twhere
T: PartialOrd,
impl<T> AsTotalOrd for Twhere
T: PartialOrd,
fn as_total_ord(&self) -> TotalOrd<&T>
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more