Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
beling committed Oct 2, 2024
1 parent b01df42 commit 3553f6b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 72 deletions.
2 changes: 1 addition & 1 deletion csf/src/fp/cmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<C: Coding, S: BuildSeededHasher> CMap<C, S> {
for i in 0..input_size {
let a_index = utils::map64_to_64(conf.hash.hash_one(&keys[i], level_nr), level_size as u64) as usize;
if collision_solver.is_under_collision(a_index) { continue }
collision_solver.process_fragment(a_index,
collision_solver.add_value(a_index,
value_coding.rev_fragment_of(values[i], value_rev_indices[i]),
value_coding.bits_per_fragment());
}
Expand Down
136 changes: 68 additions & 68 deletions csf/src/fp/collision_solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ pub trait CollisionSolver {
/// Returns true if `index` is under collision and should not be farther processed.
fn is_under_collision(&self, index: usize) -> bool;

/// Try to assign value (`bits_per_fragment` bits of `fragment`) to the given `index` which is not under collision.
fn process_fragment(&mut self, index: usize, fragment: u8, bits_per_fragment: u8);
/// Try to assign `value` (of size `bits_per_value`) to the given `index` which is not under collision.
fn add_value(&mut self, index: usize, value: u8, bits_per_value: u8);

/// Array that shows indices which have assigned values and are not under collision.
fn to_collision_array(self) -> Box<[u64]>;

/// Returns triple consisted of:
/// - an array that shows indices which have assigned values and are not under collision,
/// - values (each stored at bits_per_fragment bits) assigned to successive bit ones in the array,
/// - values (each stored at bits_per_value bits) assigned to successive bit ones in the array,
/// - number of bit ones in the array (number of values).
fn to_collision_and_values(self, bits_per_value: u8) -> (Box<[u64]>, Box<[u64]>, usize);

/// Constructs array for values to fill with `set_value` method.
fn construct_value_array(number_of_values: usize, bits_per_fragment: u8) -> Box<[u64]> {
Box::<[u64]>::with_zeroed_bits(number_of_values*bits_per_fragment as usize)
fn construct_value_array(number_of_values: usize, bits_per_value: u8) -> Box<[u64]> {
Box::<[u64]>::with_zeroed_bits(number_of_values*bits_per_value as usize)
}

/// Set `index`-th value in final `output` (which is an array of `bits_per_fragment` bits values) to `fragment`.
#[inline(always)] fn set_value(output: &mut [u64], index: usize, fragment: u8, bits_per_fragment: u8) {
output.init_fragment(index, fragment as u64, bits_per_fragment);
/// Set `index`-th value in final `output` (which is an array of `bits_per_value` bits values) to `value`.
#[inline(always)] fn set_value(output: &mut [u64], index: usize, value: u8, bits_per_value: u8) {
output.init_fragment(index, value as u64, bits_per_value);
}
}

Expand All @@ -59,9 +59,9 @@ pub trait CollisionSolverBuilder {
/// Type of collision solver that is build by `self`.
type CollisionSolver: CollisionSolver;

/// Constructs `CollisionSolver` for given number of values (64*`level_size_segments`) and `bits_per_fragment`.
/// The solver supports indices in range [0, 64*`level_size_segments`) and values of the size of `bits_per_fragment` bits.
fn new(&self, level_size_segments: usize, bits_per_fragment: u8) -> Self::CollisionSolver;
/// Constructs `CollisionSolver` for given number of values (64*`level_size_segments`) and `bits_per_value`.
/// The solver supports indices in range [0, 64*`level_size_segments`) and values of the size of `bits_per_value` bits.
fn new(&self, level_size_segments: usize, bits_per_value: u8) -> Self::CollisionSolver;

/// Gets whether the `new` method returns the collision solver that is lossless.
fn is_lossless(&self) -> bool;
Expand All @@ -75,17 +75,17 @@ pub trait IsLossless: CollisionSolverBuilder {} // TODO: maybe check only in run
pub struct LoMemAcceptEqualsSolver {
/// Which indices are under collision.
collided: Box<[u64]>,
/// Fragments assigned to indices.
fragments: Box<[u64]>,
/// Values assigned to indices.
values: Box<[u64]>,
/// Which indices have assigned values and are not under collision.
current_array: Box<[u64]>
}

impl LoMemAcceptEqualsSolver {
pub(crate) fn new(level_size_segments: usize, bits_per_fragment: u8) -> Self {
pub(crate) fn new(level_size_segments: usize, bits_per_value: u8) -> Self {
Self {
collided: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments),
fragments: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments * bits_per_fragment as usize),
values: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments * bits_per_value as usize),
current_array: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments)
}
}
Expand All @@ -96,11 +96,11 @@ impl CollisionSolver for LoMemAcceptEqualsSolver {
self.collided.get_bit(index)
}

fn process_fragment(&mut self, index: usize, fragment: u8, bits_per_fragment: u8) {
fn add_value(&mut self, index: usize, value: u8, bits_per_value: u8) {
if !self.current_array.get_bit(index) { // empty:
self.current_array.set_bit(index);
self.fragments.init_fragment(index, fragment as _, bits_per_fragment);
} else if /*fragments[a_index]*/ self.fragments.get_fragment(index, bits_per_fragment) as u8 != fragment {
self.values.init_fragment(index, value as _, bits_per_value);
} else if /*fragments[a_index]*/ self.values.get_fragment(index, bits_per_value) as u8 != value {
self.collided.set_bit(index);
self.current_array.clear_bit(index);
}
Expand All @@ -110,8 +110,8 @@ impl CollisionSolver for LoMemAcceptEqualsSolver {
self.current_array
}

fn to_collision_and_values(self, bits_per_fragment: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
let (values, len) = select_values(&self.current_array, self.fragments, bits_per_fragment);
fn to_collision_and_values(self, bits_per_value: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
let (values, len) = select_values(&self.current_array, self.values, bits_per_value);
(self.current_array, values, len)
}
}
Expand All @@ -122,8 +122,8 @@ pub struct LoMemAcceptEquals;
impl CollisionSolverBuilder for LoMemAcceptEquals {
type CollisionSolver = LoMemAcceptEqualsSolver;

#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_fragment: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_fragment)
#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_value: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_value)
}

#[inline(always)] fn is_lossless(&self) -> bool { true }
Expand All @@ -137,16 +137,16 @@ pub struct AcceptEqualsSolver {
/// Which indices are under collision.
collided: Box<[u64]>,
/// Fragments assigned to indices (uses 1 byte / value).
fragments: Box<[u8]>,
values: Box<[u8]>,
/// Which indices have assigned values and are not under collision.
current_array: Box<[u64]>
}

impl AcceptEqualsSolver {
fn new(level_size_segments: usize, _bits_per_fragment: u8) -> Self {
fn new(level_size_segments: usize, _bits_per_value: u8) -> Self {
Self {
collided: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments as usize),
fragments: vec![0u8; level_size_segments as usize * 64].into_boxed_slice(),
values: vec![0u8; level_size_segments as usize * 64].into_boxed_slice(),
current_array: Box::<[u64]>::with_zeroed_64bit_segments(level_size_segments as usize)
}
}
Expand All @@ -157,11 +157,11 @@ impl CollisionSolver for AcceptEqualsSolver {
self.collided.get_bit(index)
}

fn process_fragment(&mut self, index: usize, fragment: u8, _bits_per_fragment: u8) {
fn add_value(&mut self, index: usize, value: u8, _bits_per_value: u8) {
if !self.current_array.get_bit(index) { // empty:
self.current_array.set_bit(index);
self.fragments[index] = fragment;
} else if self.fragments[index] != fragment {
self.values[index] = value;
} else if self.values[index] != value {
self.collided.set_bit(index);
self.current_array.clear_bit(index);
}
Expand All @@ -171,8 +171,8 @@ impl CollisionSolver for AcceptEqualsSolver {
self.current_array
}

fn to_collision_and_values(self, bits_per_fragment: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
let (values, len) = select_values_f(&self.current_array, |i| self.fragments[i] as u64, bits_per_fragment);
fn to_collision_and_values(self, bits_per_value: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
let (values, len) = select_values_f(&self.current_array, |i| self.values[i] as u64, bits_per_value);
(self.current_array, values, len)
}
}
Expand All @@ -183,8 +183,8 @@ pub struct AcceptEquals;
impl CollisionSolverBuilder for AcceptEquals {
type CollisionSolver = AcceptEqualsSolver;

#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_fragment: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_fragment)
#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_value: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_value)
}

#[inline(always)] fn is_lossless(&self) -> bool { true }
Expand Down Expand Up @@ -246,14 +246,14 @@ impl AcceptLimitedAverageDifferenceSolver {
impl CollisionSolver for AcceptLimitedAverageDifferenceSolver {
#[inline(always)] fn is_under_collision(&self, _index: usize) -> bool { false }

fn process_fragment(&mut self, index: usize, fragment: u8, _bits_per_fragment: u8) {
fn add_value(&mut self, index: usize, value: u8, _bits_per_value: u8) {
let c = &mut self.cells[index];
let m = c.minimum(self.value_mask);
if fragment < m {
c.total_difference = c.total_difference.checked_add(c.get_count(self.bits_per_value) * (m - fragment) as u16).unwrap();
c.set_minimum(fragment, self.value_mask);
if value < m {
c.total_difference = c.total_difference.checked_add(c.get_count(self.bits_per_value) * (m - value) as u16).unwrap();
c.set_minimum(value, self.value_mask);
} else {
c.total_difference = c.total_difference.checked_add((fragment - m) as u16).unwrap(); // (fragment - m) can be 0 here
c.total_difference = c.total_difference.checked_add((value - m) as u16).unwrap(); // (value - m) can be 0 here
}
c.inc_count(self.bits_per_value);
}
Expand All @@ -269,25 +269,25 @@ impl CollisionSolver for AcceptLimitedAverageDifferenceSolver {
result
}

fn construct_value_array(number_of_values: usize, bits_per_fragment: u8) -> Box<[u64]> {
Box::<[u64]>::with_filled_bits(number_of_values*bits_per_fragment as usize)
fn construct_value_array(number_of_values: usize, bits_per_value: u8) -> Box<[u64]> {
Box::<[u64]>::with_filled_bits(number_of_values*bits_per_value as usize)
}

fn set_value(output: &mut [u64], index: usize, fragment: u8, bits_per_fragment: u8) {
let fragment = fragment as u64;
output.conditionally_change_fragment(| old| if fragment < old { Some(fragment) } else {None}, index, bits_per_fragment);
fn set_value(output: &mut [u64], index: usize, value: u8, bits_per_value: u8) {
let value = value as u64;
output.conditionally_change_fragment(| old| if value < old { Some(value) } else {None}, index, bits_per_value);
}

fn to_collision_and_values(self, bits_per_fragment: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
fn to_collision_and_values(self, bits_per_value: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
let mut to_select = Box::<[u64]>::with_zeroed_64bit_segments(self.cells.len() / 64);
for (index, cell) in self.cells.into_iter().enumerate() {
let d = cell.get_count(self.bits_per_value);
if d != 0 && cell.total_difference as u32 <= d as u32 * self.max_difference_per_value as u32 {
to_select.set_bit(index);
}
}
let value_mask = n_lowest_bits(bits_per_fragment) as u16;
let (values, len) = select_values_f(&to_select, |i| self.cells[i].minimum(value_mask) as u64, bits_per_fragment);
let value_mask = n_lowest_bits(bits_per_value) as u16;
let (values, len) = select_values_f(&to_select, |i| self.cells[i].minimum(value_mask) as u64, bits_per_value);
(to_select, values, len)
}
}
Expand All @@ -309,79 +309,79 @@ impl AcceptLimitedAverageDifference {
impl CollisionSolverBuilder for AcceptLimitedAverageDifference {
type CollisionSolver = AcceptLimitedAverageDifferenceSolver;

#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_fragment: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_fragment, self.max_difference_per_value)
#[inline(always)] fn new(&self, level_size_segments: usize, bits_per_value: u8) -> Self::CollisionSolver {
Self::CollisionSolver::new(level_size_segments, bits_per_value, self.max_difference_per_value)
}

#[inline(always)] fn is_lossless(&self) -> bool { self.max_difference_per_value == 0 }
}


pub struct CountPositiveCollisions {
count_and_fragments: Box<[u16]>
count_and_values: Box<[u16]>
}

impl CountPositiveCollisions {
pub fn new(level_size: usize) -> Self {
CountPositiveCollisions {
count_and_fragments: vec![0; level_size].into_boxed_slice()
count_and_values: vec![0; level_size].into_boxed_slice()
}
}

pub fn consider(count_and_fragment: &mut u16, fragment: u16, bits_per_fragment: u8) {
if *count_and_fragment == 0 { // empty?
*count_and_fragment = (1u16 << bits_per_fragment) | fragment;
} else if *count_and_fragment & ((1u16 << bits_per_fragment) - 1) == fragment { // the same fragment again
if let Some(v) = count_and_fragment.checked_add(1 << bits_per_fragment) {
*count_and_fragment = v;
pub fn consider(count_and_values: &mut u16, value: u16, bits_per_value: u8) {
if *count_and_values == 0 { // empty?
*count_and_values = (1u16 << bits_per_value) | value;
} else if *count_and_values & ((1u16 << bits_per_value) - 1) == value { // the same value again
if let Some(v) = count_and_values.checked_add(1 << bits_per_value) {
*count_and_values = v;
}
} else { // collision:
*count_and_fragment = u16::MAX;
*count_and_values = u16::MAX;
}
}

/// Returns number of positive collision in given `entry`.
#[inline] pub fn positive_collisions_in_entry(entry: u16, bits_per_fragment: u8) -> u16 {
#[inline] pub fn positive_collisions_in_entry(entry: u16, bits_per_value: u8) -> u16 {
if entry == u16::MAX { // collision
0
} else {
entry >> bits_per_fragment
entry >> bits_per_value
}
}

/// Returns number of positive collision at given `index`.
#[inline] pub fn count(&self, index: usize, bits_per_fragment: u8) -> u16 {
Self::positive_collisions_in_entry(self.count_and_fragments[index], bits_per_fragment)
#[inline] pub fn count(&self, index: usize, bits_per_value: u8) -> u16 {
Self::positive_collisions_in_entry(self.count_and_values[index], bits_per_value)
}

pub fn len(&self) -> usize { self.count_and_fragments.len() }
pub fn len(&self) -> usize { self.count_and_values.len() }

/// Counts total number of positive collision in each group (chunk) of successive `values_per_group` indices.
pub fn positive_collisions_of_groups(&self, values_per_group: u8, bits_per_fragment: u8) -> Box<[u8]> {
self.count_and_fragments
pub fn positive_collisions_of_groups(&self, values_per_group: u8, bits_per_value: u8) -> Box<[u8]> {
self.count_and_values
.chunks(values_per_group as usize)
.map(|v|
v.iter()
.map(|e| Self::positive_collisions_in_entry(*e, bits_per_fragment))
.map(|e| Self::positive_collisions_in_entry(*e, bits_per_value))
.fold(0u8, |sum, x| sum.saturating_add(x.min(u8::MAX as _) as u8))
).collect()
}
}

impl CollisionSolver for CountPositiveCollisions {
fn is_under_collision(&self, index: usize) -> bool {
self.count_and_fragments[index] == u16::MAX
self.count_and_values[index] == u16::MAX
}

fn process_fragment(&mut self, index: usize, fragment: u8, bits_per_fragment: u8) {
Self::consider(&mut self.count_and_fragments[index], fragment as u16, bits_per_fragment);
fn add_value(&mut self, index: usize, value: u8, bits_per_value: u8) {
Self::consider(&mut self.count_and_values[index], value as u16, bits_per_value);
}

fn to_collision_array(self) -> Box<[u64]> {
todo!()
}

fn to_collision_and_values(self, _bits_per_fragment: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
fn to_collision_and_values(self, _bits_per_value: u8) -> (Box<[u64]>, Box<[u64]>, usize) {
todo!()
}
}
2 changes: 1 addition & 1 deletion csf/src/fp/gocmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<C: Coding, GS: GroupSize, SS: SeedSize, S: BuildSeededHasher> GOCMap<C, GS,
let group = group_nr(hash, level_size_groups);
let index = conf.goconf.bits_per_group.bit_index_for_seed(hash, group_seed(group), group);
if collision_solver.is_under_collision(index) { continue }
collision_solver.process_fragment(index,
collision_solver.add_value(index,
coding.rev_fragment_of(values[i], value_rev_indices[i]),
bits_per_fragment);
}
Expand Down
4 changes: 2 additions & 2 deletions csf/src/fp/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl<S: BuildSeededHasher> Map<S> {
kv.for_each_key_value(|k, v| { // TODO ?? move this code to kv method
let a_index = utils::map64_to_64(conf.hash.hash_one(k, level_nr), level_size as u64) as usize;
if !collision_solver.is_under_collision(a_index) {
collision_solver.process_fragment(a_index, v, bits_per_value);
collision_solver.add_value(a_index, v, bits_per_value);
}
});
let (current_array, current_values, current_values_len) = collision_solver.to_collision_and_values(bits_per_value);
Expand Down Expand Up @@ -124,7 +124,7 @@ impl<S: BuildSeededHasher> Map<S> {

/// Build `Map` for given keys -> values map, where:
/// - keys are given directly,
/// - TODO values are given as bit vector with bit_per_value.
/// - values are given as bit vector with bit_per_value.
/// These arrays must be of the same length.
fn with_slices_conf_stats<K, LSC, CSB, BS>(
keys: &mut [K], values: &mut [u8],
Expand Down

0 comments on commit 3553f6b

Please sign in to comment.