Add more functionality to BitMatrix
This commit is contained in:
parent
a38991f755
commit
66e7493543
2 changed files with 93 additions and 1 deletions
|
@ -636,7 +636,7 @@ impl<T: Idx> GrowableBitSet<T> {
|
|||
///
|
||||
/// All operations that involve a row and/or column index will panic if the
|
||||
/// index exceeds the relevant bound.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
|
||||
pub struct BitMatrix<R: Idx, C: Idx> {
|
||||
num_rows: usize,
|
||||
num_columns: usize,
|
||||
|
@ -658,6 +658,23 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new matrix, with `row` used as the value for every row.
|
||||
pub fn from_row_n(row: &BitSet<C>, num_rows: usize) -> BitMatrix<R, C> {
|
||||
let num_columns = row.domain_size();
|
||||
let words_per_row = num_words(num_columns);
|
||||
assert_eq!(words_per_row, row.words().len());
|
||||
BitMatrix {
|
||||
num_rows,
|
||||
num_columns,
|
||||
words: iter::repeat(row.words()).take(num_rows).flatten().cloned().collect(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rows(&self) -> impl Iterator<Item = R> {
|
||||
(0..self.num_rows).map(R::new)
|
||||
}
|
||||
|
||||
/// The range of bits for a given row.
|
||||
fn range(&self, row: R) -> (usize, usize) {
|
||||
let words_per_row = num_words(self.num_columns);
|
||||
|
@ -737,6 +754,49 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
|
|||
changed
|
||||
}
|
||||
|
||||
/// Adds the bits from `with` to the bits from row `write`, and
|
||||
/// returns `true` if anything changed.
|
||||
pub fn union_row_with(&mut self, with: &BitSet<C>, write: R) -> bool {
|
||||
assert!(write.index() < self.num_rows);
|
||||
assert_eq!(with.domain_size(), self.num_columns);
|
||||
let (write_start, write_end) = self.range(write);
|
||||
let mut changed = false;
|
||||
for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) {
|
||||
let word = self.words[write_index];
|
||||
let new_word = word | with.words()[read_index];
|
||||
self.words[write_index] = new_word;
|
||||
changed |= word != new_word;
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
/// Sets every cell in `row` to true.
|
||||
pub fn insert_all_into_row(&mut self, row: R) {
|
||||
assert!(row.index() < self.num_rows);
|
||||
let (start, end) = self.range(row);
|
||||
let words = &mut self.words[..];
|
||||
for index in start..end {
|
||||
words[index] = !0;
|
||||
}
|
||||
self.clear_excess_bits(row);
|
||||
}
|
||||
|
||||
/// Clear excess bits in the final word of the row.
|
||||
fn clear_excess_bits(&mut self, row: R) {
|
||||
let num_bits_in_final_word = self.num_columns % WORD_BITS;
|
||||
if num_bits_in_final_word > 0 {
|
||||
let mask = (1 << num_bits_in_final_word) - 1;
|
||||
let (_, end) = self.range(row);
|
||||
let final_word_idx = end - 1;
|
||||
self.words[final_word_idx] &= mask;
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a slice of the underlying words.
|
||||
pub fn words(&self) -> &[Word] {
|
||||
&self.words
|
||||
}
|
||||
|
||||
/// Iterates through all the columns set to true in a given row of
|
||||
/// the matrix.
|
||||
pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
|
||||
|
@ -748,6 +808,12 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
|
|||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of elements in `row`.
|
||||
pub fn count(&self, row: R) -> usize {
|
||||
let (start, end) = self.range(row);
|
||||
self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
|
||||
}
|
||||
}
|
||||
|
||||
/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
|
||||
|
@ -1057,6 +1123,7 @@ fn matrix_iter() {
|
|||
matrix.insert(2, 99);
|
||||
matrix.insert(4, 0);
|
||||
matrix.union_rows(3, 5);
|
||||
matrix.insert_all_into_row(6);
|
||||
|
||||
let expected = [99];
|
||||
let mut iter = expected.iter();
|
||||
|
@ -1068,6 +1135,7 @@ fn matrix_iter() {
|
|||
|
||||
let expected = [22, 75];
|
||||
let mut iter = expected.iter();
|
||||
assert_eq!(matrix.count(3), expected.len());
|
||||
for i in matrix.iter(3) {
|
||||
let j = *iter.next().unwrap();
|
||||
assert_eq!(i, j);
|
||||
|
@ -1076,6 +1144,7 @@ fn matrix_iter() {
|
|||
|
||||
let expected = [0];
|
||||
let mut iter = expected.iter();
|
||||
assert_eq!(matrix.count(4), expected.len());
|
||||
for i in matrix.iter(4) {
|
||||
let j = *iter.next().unwrap();
|
||||
assert_eq!(i, j);
|
||||
|
@ -1084,11 +1153,24 @@ fn matrix_iter() {
|
|||
|
||||
let expected = [22, 75];
|
||||
let mut iter = expected.iter();
|
||||
assert_eq!(matrix.count(5), expected.len());
|
||||
for i in matrix.iter(5) {
|
||||
let j = *iter.next().unwrap();
|
||||
assert_eq!(i, j);
|
||||
}
|
||||
assert!(iter.next().is_none());
|
||||
|
||||
assert_eq!(matrix.count(6), 100);
|
||||
let mut count = 0;
|
||||
for (idx, i) in matrix.iter(6).enumerate() {
|
||||
assert_eq!(idx, i);
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 100);
|
||||
|
||||
if let Some(i) = matrix.iter(7).next() {
|
||||
panic!("expected no elements in row, but contains element {:?}", i);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -503,6 +503,16 @@ impl<I: indexed_vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I>
|
|||
}
|
||||
}
|
||||
|
||||
impl<R: indexed_vec::Idx, C: indexed_vec::Idx, CTX> HashStable<CTX>
|
||||
for bit_set::BitMatrix<R, C>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
ctx: &mut CTX,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.words().hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_via_hash!(::std::path::Path);
|
||||
impl_stable_hash_via_hash!(::std::path::PathBuf);
|
||||
|
||||
|
|
Loading…
Reference in a new issue