Skip to content

Commit

Permalink
Merge pull request #51 from kitsuyui/implement-access-rank-select-ope…
Browse files Browse the repository at this point in the history
…rators

Implement access rank select operators
  • Loading branch information
kitsuyui authored Nov 11, 2024
2 parents 14e7652 + 2ace204 commit 8eaf67d
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 0 deletions.
139 changes: 139 additions & 0 deletions src/bitline/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,4 +382,143 @@ pub trait Bitline {
/// assert_eq!(bitline.two_bits_gray_code_rotation(), 0b01111000_u8);
/// ```
fn two_bits_gray_code_rotation(&self) -> Self;

/// Access the specified position in the bit sequence and get the value of the bit.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.access(0), false);
/// assert_eq!(bitline.access(1), false);
/// assert_eq!(bitline.access(2), false);
/// assert_eq!(bitline.access(3), true);
/// assert_eq!(bitline.access(4), true);
/// ```
fn access(&self, index: usize) -> bool;

/// Count how many times 0 appears up to the index (i-th) position.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank_0(0), 0);
/// assert_eq!(bitline.rank_0(1), 1);
/// assert_eq!(bitline.rank_0(2), 2);
/// assert_eq!(bitline.rank_0(5), 3);
/// ```
fn rank_0(&self, index: usize) -> usize;

/// Count how many times 1 appears up to the index (i-th) position.
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank_1(0), 0);
/// assert_eq!(bitline.rank_1(1), 0);
/// assert_eq!(bitline.rank_1(2), 0);
/// assert_eq!(bitline.rank_1(3), 0);
/// assert_eq!(bitline.rank_1(4), 1);
/// assert_eq!(bitline.rank_1(5), 2);
/// assert_eq!(bitline.rank_1(6), 3);
/// assert_eq!(bitline.rank_1(7), 4);
/// assert_eq!(bitline.rank_1(8), 4);
/// ```
fn rank_1(&self, index: usize) -> usize;

/// Count how many times specified bit appears up to the index (i-th) position.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank(0, false), 0);
/// assert_eq!(bitline.rank(1, false), 1);
/// assert_eq!(bitline.rank(2, false), 2);
/// assert_eq!(bitline.rank(3, true), 0);
/// ```
fn rank(&self, index: usize, bit: bool) -> usize;

/// Count how many times 0 appears between the begin (i-th) and the end (j-th) positions.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank_range_0(0, 1), 1);
/// assert_eq!(bitline.rank_range_0(0, 3), 3);
/// assert_eq!(bitline.rank_range_0(0, 4), 3);
/// ```
fn rank_range_0(&self, begin: usize, end: usize) -> usize;

/// Count how many times 1 appears between the begin (i-th) and the end (j-th) positions.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank_range_1(0, 1), 0);
/// assert_eq!(bitline.rank_range_1(0, 3), 0);
/// assert_eq!(bitline.rank_range_1(0, 4), 1);
/// assert_eq!(bitline.rank_range_1(3, 5), 2);
/// ```
fn rank_range_1(&self, begin: usize, end: usize) -> usize;

/// Count how many times specified bit appears between the begin (i-th) and the end (j-th) positions.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.rank_range(0, 1, false), 1);
/// assert_eq!(bitline.rank_range(0, 3, false), 3);
/// assert_eq!(bitline.rank_range(0, 4, false), 3);
/// assert_eq!(bitline.rank_range(0, 4, true), 1);
/// ```
fn rank_range(&self, begin: usize, end: usize, bit: bool) -> usize;

/// Find the position where the n-th 0 appears.
/// If there is no n-th 0, return None.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.select_0(0), Some(0));
/// assert_eq!(bitline.select_0(1), Some(1));
/// assert_eq!(bitline.select_0(2), Some(2));
/// assert_eq!(bitline.select_0(3), Some(7));
/// assert_eq!(bitline.select_0(4), None);
/// ```
fn select_0(&self, nth: usize) -> Option<usize>;

/// Find the position where the n-th 1 appears.
/// If there is no n-th 1, return None.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.select_1(0), Some(3));
/// assert_eq!(bitline.select_1(1), Some(4));
/// assert_eq!(bitline.select_1(2), Some(5));
/// assert_eq!(bitline.select_1(3), Some(6));
/// assert_eq!(bitline.select_1(4), None);
/// ```
fn select_1(&self, nth: usize) -> Option<usize>;

/// Find the position where the n-th specified bit appears.
/// If there is no n-th specified bit, return None.
///
/// # Examples
/// ```
/// use bittersweet::bitline::{Bitline, Bitline8};
/// let bitline = 0b00011110_u8;
/// assert_eq!(bitline.select(0, false), Some(0));
/// assert_eq!(bitline.select(1, false), Some(1));
/// assert_eq!(bitline.select(2, false), Some(2));
/// assert_eq!(bitline.select(0, true), Some(3));
/// ```
fn select(&self, nth: usize, bit: bool) -> Option<usize>;
}
151 changes: 151 additions & 0 deletions src/bitline/uints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,98 @@ macro_rules! impl_Bitline {
let l = ((!self) & Self::mask_10()) >> 1;
r | l
}

#[inline]
fn access(&self, index: usize) -> bool {
(*self & (1 << (Self::length() - index - 1))) != 0
}

#[inline]
fn rank_0(&self, index: usize) -> usize {
let mask_range = !Self::by_range(0, index);
(*self | mask_range).count_zeros() as usize
}

#[inline]
fn rank_1(&self, index: usize) -> usize {
let mask_range = !Self::by_range(0, index);
(*self & !mask_range).count_ones() as usize
}

#[inline]
fn rank(&self, index: usize, bit: bool) -> usize {
if bit {
self.rank_1(index)
} else {
self.rank_0(index)
}
}

#[inline]
fn rank_range_0(&self, begin: usize, end: usize) -> usize {
let mask_begin = Self::by_range(0, begin);
let mask_end = Self::by_range(end, Self::length());
let mask = mask_begin | mask_end;
(*self | mask).count_zeros() as usize
}

#[inline]
fn rank_range_1(&self, begin: usize, end: usize) -> usize {
let mask_begin = Self::by_range(0, begin);
let mask_end = Self::by_range(end, Self::length());
let mask = mask_begin | mask_end;
(*self & !mask).count_ones() as usize
}

#[inline]
fn rank_range(&self, begin: usize, end: usize, bit: bool) -> usize {
if bit {
self.rank_range_1(begin, end)
} else {
self.rank_range_0(begin, end)
}
}

#[inline]
fn select_0(&self, nth: usize) -> Option<usize> {
// TODO: naive implementation. improve performance.
let mut count = 0;
for i in 0..Self::length() {
if (self.access(i)) {
continue;
}
if (count == nth) {
return Some(i);
}
count += 1;
}
None
}

#[inline]
fn select_1(&self, nth: usize) -> Option<usize> {
// TODO: naive implementation. improve performance.
let mut count = 0;
for i in 0..Self::length() {
if (!self.access(i)) {
continue;
}
if (count == nth) {
return Some(i);
}
count += 1;
}
None
}

#[inline]
fn select(&self, nth: usize, bit: bool) -> Option<usize> {
if bit {
self.select_1(nth)
} else {
self.select_0(nth)
}
}
}
};
}
Expand Down Expand Up @@ -657,6 +749,65 @@ mod tests {
});
}

#[test]
fn test_access() {
assert!(!0b00000000_u8.access(0));
assert!(!0b00000000_u8.access(1));
assert!(!0b00000000_u8.access(2));
assert!(!0b00000000_u8.access(3));
assert!(0b00001000_u8.access(4));
assert!(!0b00001000_u8.access(5));
assert!(!0b00001000_u8.access(6));
assert!(!0b00001000_u8.access(7));
}

#[test]
fn test_rank_operations() {
// rank(index, true) is equivalent to rank_1(index)
// rank(index, false) is equivalent to rank_0(index)
for bitline in 0..256 {
let bitline = bitline as u8;
for i in 0..8 {
assert_eq!(bitline.rank(i as usize, true), bitline.rank_1(i as usize));
assert_eq!(bitline.rank(i as usize, false), bitline.rank_0(i as usize));
}
}
// rank_range(0, index, true) is equivalent to rank_range_1(0, index)
// rank_range(0, index, false) is equivalent to rank_range_0(0, index)
for bitline in 0..256 {
let bitline = bitline as u8;
for i in 0..8 {
assert_eq!(
bitline.rank_range(0, i as usize, true),
bitline.rank_range_1(0, i as usize)
);
assert_eq!(
bitline.rank_range(0, i as usize, false),
bitline.rank_range_0(0, i as usize)
);
}
}
}

#[test]
fn test_select_operations() {
// select(nth, true) is equivalent to select_1(nth)
// select(nth, false) is equivalent to select_0(nth)
for bitline in 0..256 {
let bitline = bitline as u8;
for i in 0..8 {
assert_eq!(
bitline.select(i as usize, true),
bitline.select_1(i as usize)
);
assert_eq!(
bitline.select(i as usize, false),
bitline.select_0(i as usize)
);
}
}
}

fn assert_bijection(function: fn(u8) -> u8) {
// bijection means no collision.
let mut counter = HashMap::new();
Expand Down

0 comments on commit 8eaf67d

Please sign in to comment.