From b6a04efc9e94f35b49fd286cd0e81fcc6bc56432 Mon Sep 17 00:00:00 2001 From: Sam Cutler Date: Mon, 15 Sep 2025 17:00:25 +0100 Subject: [PATCH 1/4] initial import --- Cargo.toml | 4 +- crates/hriblt/Cargo.toml | 12 + crates/hriblt/README.md | 55 +++ .../docs/assets/coded-symbol-multiplier.png | Bin 0 -> 17282 bytes crates/hriblt/docs/hashing_functions.md | 21 + crates/hriblt/docs/sizing.md | 17 + crates/hriblt/src/coded_symbol.rs | 127 ++++++ crates/hriblt/src/decoded_value.rs | 31 ++ crates/hriblt/src/decoding_session.rs | 221 ++++++++++ crates/hriblt/src/encoding_session.rs | 284 +++++++++++++ crates/hriblt/src/error.rs | 22 + crates/hriblt/src/lib.rs | 400 ++++++++++++++++++ 12 files changed, 1192 insertions(+), 2 deletions(-) create mode 100644 crates/hriblt/Cargo.toml create mode 100644 crates/hriblt/README.md create mode 100644 crates/hriblt/docs/assets/coded-symbol-multiplier.png create mode 100644 crates/hriblt/docs/hashing_functions.md create mode 100644 crates/hriblt/docs/sizing.md create mode 100644 crates/hriblt/src/coded_symbol.rs create mode 100644 crates/hriblt/src/decoded_value.rs create mode 100644 crates/hriblt/src/decoding_session.rs create mode 100644 crates/hriblt/src/encoding_session.rs create mode 100644 crates/hriblt/src/error.rs create mode 100644 crates/hriblt/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 312f46d..ad992f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [ "crates/*", "crates/bpe/benchmarks", - "crates/bpe/tests", + "crates/bpe/tests" ] resolver = "2" @@ -11,4 +11,4 @@ resolver = "2" debug = true [profile.release] -debug = true \ No newline at end of file +debug = true diff --git a/crates/hriblt/Cargo.toml b/crates/hriblt/Cargo.toml new file mode 100644 index 0000000..91f8585 --- /dev/null +++ b/crates/hriblt/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "hriblt" +version = "0.1.0" +edition = "2024" +description = "Algorithm for rateless set reconciliation" +repository = "https://github.com/github/rust-gems" +license = "MIT" +keywords = ["set-reconciliation", "sync", "algorithm", "probabilistic"] +categories = ["algorithms", "data-structures", "mathematics", "science"] + +[dependencies] +thiserror = "2" diff --git a/crates/hriblt/README.md b/crates/hriblt/README.md new file mode 100644 index 0000000..6b93d8b --- /dev/null +++ b/crates/hriblt/README.md @@ -0,0 +1,55 @@ +# Hierarchical Rateless Bloom Lookup Tables + +A novel algorithm for computing the symmetric difference between sets where the amount of data shared is proportional to the size of the difference in the sets rather than proportional to the overall size. + +## Usage + +Add the library to your `Cargo.toml` file. + +```toml +[dependencies] +hriblt = "0.1" +``` + +Create two encoding sessions, one containing your data, and another containing the counter-parties data. This counterparty data might have been sent to you over a network for example. + +The following example attempts to reconcile the differences between two sets of `u64` integers, and is done from the perspective of "Bob", who has recieved some symbols from "Alice". + +```rust +use hriblt::{DecodingSession, EncodingSession, DefaultHashFunctions}; +// On Alice's computer + +// Alice creates an encoding session... +let mut alice_encoding_session = EncodingSession::::new(DefaultHashFunctions, 0..128); + +// And adds her data to that session, in this case the numbers from 0 to 10. +for i in 0..=10 { + alice_encoding_session.insert(i); +} + +// On Bob's computer + +// Bob creates his encoding session, note that the range **must** be the same as Alice's +let mut bob_encoding_session = EncodingSession::::new(DefaultHashFunctions, 0..128); + +// Bob adds his data, the numbers from 5 to 15. +for i in 5..=15 { + bob_encoding_session.insert(i); +} + +// "Subtract" Bob's coded symbols from Alice's, the remaining symbols will be the symmetric +// difference between the two sets, iff we can decode them. This is a commutative function so you +// could also subtract Alice's symbols from Bob's and it would still work. +let merged_sessions = alice_encoding_session.merge(bob_encoding_session, true); + +let decoding_session = DecodingSession::from_encoding(merged_sessions); + +assert!(decoding_session.is_done()); + +let mut diff = decoding_session.into_decoded_iter().map(|v| v.into_value()).collect::>(); + +diff.sort(); + +assert_eq!(diff, [0, 1, 2, 3, 4, 11, 12, 13, 14, 15]); + +``` diff --git a/crates/hriblt/docs/assets/coded-symbol-multiplier.png b/crates/hriblt/docs/assets/coded-symbol-multiplier.png new file mode 100644 index 0000000000000000000000000000000000000000..84d3b694d848a0b6d4f30a7715425caf757b9253 GIT binary patch literal 17282 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 { + /// Values aggregated by XOR operation. + pub value: T, + /// We repurpose the two least significant bits of the checksum: + /// - The least significant bit is a one bit counter which is incremented for each entity. + /// This bit must be set when there is a single entity represented by this hash. + /// - The second least significant bit indicates whether the entity is a deletion or insertion. + pub checksum: u64, +} + +impl Default for CodedSymbol { + fn default() -> Self { + CodedSymbol { + value: T::zero(), + checksum: 0, + } + } +} + +impl From<(T, u64)> for CodedSymbol { + fn from(tuple: (T, u64)) -> Self { + Self { + value: tuple.0, + checksum: tuple.1, + } + } +} + +impl CodedSymbol { + /// Creates a new coded symbol with the given hash and deletion flag. + pub(crate) fn new>(state: &S, hash: T, deletion: bool) -> Self { + let mut checksum = state.check_sum(&hash); + checksum |= 1; // Add a single bit counter + if deletion { + checksum = checksum.wrapping_neg(); + } + CodedSymbol { + value: hash, + checksum, + } + } + + /// Merges another coded symbol into this one. + pub(crate) fn add(&mut self, other: &CodedSymbol, negate: bool) { + self.value.xor(other.value); + if negate { + self.checksum = self.checksum.wrapping_sub(other.checksum); + } else { + self.checksum = self.checksum.wrapping_add(other.checksum); + } + } + + /// Checks whether this coded symbol is pure, i.e., whether it represents a single entity + /// A pure coded symbol must satisfy the following conditions: + /// - The 1-bit counter must be 1 or -1 (which are both represented by the bit being set) + /// - The checksum must match the checksum of the value. + /// - The indices of the value must match the index of this coded symbol. + pub(crate) fn is_pure>( + &self, + state: &S, + i: usize, + len: usize, + ) -> (bool, usize) { + if self.checksum & 1 == 0 { + return (false, 0); + } + let multiplicity = indices_contains(state, &self.value, len, i); + if multiplicity != 1 { + return (false, 0); + } + let checksum = state.check_sum(&self.value) | 1; + if checksum == self.checksum || checksum.wrapping_neg() == self.checksum { + (true, 0) + } else { + let required_bits = self + .checksum + .wrapping_sub(checksum) + .leading_zeros() + .max(self.checksum.wrapping_add(checksum).leading_zeros()) + as usize; + (false, required_bits) + } + } + + /// Checks whether this coded symbol is zero, i.e., whether it represents no entity. + pub(crate) fn is_zero(&self) -> bool { + self.checksum == 0 && self.value == T::zero() + } + + /// Checks whether this coded symbol represents a deletion. + pub(crate) fn is_deletion>(&self, state: &S) -> bool { + let checksum = state.check_sum(&self.value) | 1; + checksum != self.checksum + } +} + +/// This function checks efficiently whether the given index is contained in the indices. +/// +/// Note: we have constructed the indices such that we can determine from the last 5 bits +/// which hash function would map to this index. Therefore, we only need to check against +/// a single hash function and not all 5! +/// The only exception is for very small indices (0..32) or if the index is a multiple of 32. +/// +/// The function returns the multiplicity, i.e. how many indices hit this particular index. +/// Thereby, it takes into account whether the value is stored negated or not. +fn indices_contains( + state: &impl HashFunctions, + value: &T, + stream_len: usize, + i: usize, +) -> i32 { + if stream_len > 32 && i % 32 != 0 { + let seed = i % 4; + let j = index_for_seed(state, value, stream_len, seed as u32); + if i == j { 1 } else { 0 } + } else { + indices(state, value, stream_len) + .map(|j| if j == i { 1 } else { 0 }) + .sum() + } +} diff --git a/crates/hriblt/src/decoded_value.rs b/crates/hriblt/src/decoded_value.rs new file mode 100644 index 0000000..a7aac07 --- /dev/null +++ b/crates/hriblt/src/decoded_value.rs @@ -0,0 +1,31 @@ +/// A value that has been found by the set reconciliation algorithm. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum DecodedValue { + /// A value that has been added + Addition(T), + /// A value that has been removed + Deletion(T), +} + +impl DecodedValue { + /// Consume this `DecodedValue` to return the value + pub fn into_value(self) -> T { + match self { + DecodedValue::Addition(v) => v, + DecodedValue::Deletion(v) => v, + } + } + + /// Borrow the value within this decoded value. + pub fn value(&self) -> &T { + match self { + DecodedValue::Addition(v) => v, + DecodedValue::Deletion(v) => v, + } + } + + /// Returns true if this decoded value is a deletion + pub fn is_deletion(&self) -> bool { + matches!(self, DecodedValue::Deletion(_)) + } +} diff --git a/crates/hriblt/src/decoding_session.rs b/crates/hriblt/src/decoding_session.rs new file mode 100644 index 0000000..37bfe6e --- /dev/null +++ b/crates/hriblt/src/decoding_session.rs @@ -0,0 +1,221 @@ +use std::collections::HashSet; + +use crate::{ + Encodable, HashFunctions, coded_symbol::CodedSymbol, decoded_value::DecodedValue, + encoding_session::EncodingSession, error::SetReconciliationError, parent, +}; + +/// A session for decoding a stream of hashes. +#[derive(Clone)] +pub struct DecodingSession> { + /// The encoded stream of hashes. + /// All recovered coded symbols have been removed from this stream. + /// If decoded failed, then one can simply append more data and continue decoding. + encoded: EncodingSession, + /// All the recovered coded symbols. + recovered: Vec>, + /// Don't decode the same coded symbol multiple times (it might occur up to 5 times in the stream!). + visited: HashSet, + /// Tracks the number of non-zero coded symbol up to the split point. + pub(crate) non_zero: isize, + + /// For statistical purposes: this number informs how many bits of the + /// checksum were required to identify pure coded symbols. + pub(crate) required_bits: usize, +} + +impl> DecodingSession { + /// Create a new decoding session with a given seed. + pub fn new(state: H) -> Self { + DecodingSession { + recovered: vec![], + encoded: EncodingSession::new(state, 0..0), + visited: HashSet::default(), + non_zero: 0, + required_bits: 0, + } + } + + fn from_encoding_unchecked(merged: EncodingSession) -> Self { + let mut me = DecodingSession { + recovered: vec![], + encoded: merged, + visited: HashSet::default(), + non_zero: 0, + required_bits: 0, + }; + // We work here with a non-hierarchical stream. + me.encoded.move_split_point(me.encoded.range.end); + me.non_zero = me + .encoded + .coded_symbols + .iter() + .filter(|e| !e.is_zero()) + .count() as isize; + let mut j = me.recovered.len(); + let len = me.encoded.coded_symbols.len(); + for i in (0..len).rev() { + if me.non_zero == 0 { + break; + } + let (is_pure, required_bits) = me.encoded.is_pure(i); + if is_pure && !me.visited.contains(&me.encoded.coded_symbols[i].value) { + me.visited.insert(me.encoded.coded_symbols[i].value); + me.recovered.push(me.encoded.coded_symbols[i]); + } + if !is_pure && required_bits > me.required_bits { + me.required_bits = required_bits; + } + while j < me.recovered.len() { + let entity = me.recovered[j]; + let (changes, required_bits) = + me.encoded.add_to_stream(&entity, true, i + 1..len, |e, k| { + assert!(k > i); + if !me.visited.contains(&e.value) { + me.visited.insert(e.value); + me.recovered.push(e); + } + }); + me.non_zero += changes; + me.required_bits = me.required_bits.max(required_bits); + j += 1; + } + } + me + } + + /// This is a faster version for decoding the initial stream. + /// It processes this stream from back to front without going through the hierarchical representation. + /// The other procedure needs to execute roughly one additional `is_pure` test when unrolling the hierarchy + /// which this procedure avoids. + /// Additionally, this procedure can save on average another 50% of is_pure tests, since it won't waste time + /// on the highly packed hierarchy levels where we don't expect to find any pure values. + /// + /// Panics if the encoding session is not the beginning of a stream (e.g. the range is `0..n`) + pub fn from_encoding(merged: EncodingSession) -> Self { + assert_eq!(merged.range.start, 0); + Self::from_encoding_unchecked(merged) + } + + /// This is a faster version for decoding the initial stream. + /// It processes this stream from back to front without going through the hierarchical representation. + /// The other procedure needs to execute roughly one additional `is_pure` test when unrolling the hierarchy + /// which this procedure avoids. + /// Additionally, this procedure can save on average another 50% of is_pure tests, since it won't waste time + /// on the highly packed hierarchy levels where we don't expect to find any pure values. + /// + /// Returns an error if the encoding session is not the beginning of a stream (e.g. the range is `0..n`) + pub fn try_from_encoding( + merged: EncodingSession, + ) -> Result { + if merged.range.start != 0 { + return Err(SetReconciliationError::NotInitialRange); + } + Ok(Self::from_encoding_unchecked(merged)) + } + + fn append_unchecked(&mut self, mut merged: EncodingSession) { + // Apply all the reconstructed entities to the new part of the stream. + for entity in &self.recovered { + merged.add_entity_inner(entity, true); + } + assert_eq!(self.encoded.split, self.encoded.range.end); + self.encoded.append(merged); + // Now continue decoding starting with the newly arrived data. + let mut j = self.recovered.len(); + for i in self.encoded.split..self.encoded.range.end { + // Undo hierarchy manually here, since we also need to count non-zero entries along the way. + let ii = parent(i); + if i > 0 { + let tmp = self.encoded.coded_symbols[i]; + if !self.encoded.is_zero(ii) { + self.non_zero -= 1; + } + self.encoded.coded_symbols[ii].add(&tmp, true); + if !self.encoded.is_zero(ii) { + self.non_zero += 1; + } + } + self.encoded.split = i + 1; + if !self.encoded.is_zero(i) { + self.non_zero += 1; + } + for l in [i, ii] { + let (is_pure, required_bits) = self.encoded.is_pure(l); + if is_pure && !self.visited.contains(&self.encoded.coded_symbols[l].value) { + self.visited.insert(self.encoded.coded_symbols[l].value); + self.recovered.push(self.encoded.coded_symbols[l]); + } + if !is_pure && required_bits > self.required_bits { + self.required_bits = required_bits; + } + } + while j < self.recovered.len() { + let entity = self.recovered[j]; + let (changes, required_bits) = + self.encoded.add_to_stream(&entity, true, 0..i, |e, k| { + assert!(k < i); + if !self.visited.contains(&e.value) { + self.visited.insert(e.value); + self.recovered.push(e); + } + }); + self.non_zero += changes; + self.required_bits = self.required_bits.max(required_bits); + j += 1; + } + if self.non_zero == 0 { + // At this point everything should be decoded... + // We could in theory check that all remaining coded symbols are zero. + break; + } + } + } + + /// Appends the next chunk of coded symbols to the decoding session. + /// This should only be called if decoding was not yet completed. + /// Panics if the encoding session is not a contiguous range with `self`. + pub fn append(&mut self, merged: EncodingSession) { + assert_eq!(self.encoded.range.end, merged.range.start); + self.append_unchecked(merged); + } + + /// Appends the next chunk of coded symbols to the decoding session. + /// This should only be called if decoding was not yet completed. + /// Returns an error if the encoding session is not a contiguous range with `self`. + pub fn try_append( + &mut self, + merged: EncodingSession, + ) -> Result<(), SetReconciliationError> { + if self.encoded.range.end != merged.range.start { + return Err(SetReconciliationError::NonContiguousRanges); + } + self.append_unchecked(merged); + Ok(()) + } + + /// Returns whether decoding has successfully finished. + pub fn is_done(&self) -> bool { + !self.encoded.coded_symbols.is_empty() && self.non_zero == 0 + } + + /// Returns the number of coded symbols that were consumed during the decoding process. + pub fn consumed_coded_symbols(&self) -> usize { + self.encoded.split + } + + /// Extract the decoded entities from the session. + /// Only call when `is_done()` returns true. + pub fn into_decoded_iter(self) -> impl Iterator> { + // We have decoded the stream successfully. + // Now we can return the decoded entities. + let hasher = self.encoded.hasher; + self.recovered.into_iter().map(move |e| { + if e.is_deletion(&hasher) { + DecodedValue::Deletion(e.value) + } else { + DecodedValue::Addition(e.value) + } + }) + } +} diff --git a/crates/hriblt/src/encoding_session.rs b/crates/hriblt/src/encoding_session.rs new file mode 100644 index 0000000..69538f3 --- /dev/null +++ b/crates/hriblt/src/encoding_session.rs @@ -0,0 +1,284 @@ +use std::ops::Range; + +use crate::{ + Encodable, HashFunctions, coded_symbol::CodedSymbol, error::SetReconciliationError, indices, + parent, +}; + +/// A session for encoding a stream of values. +/// This session can be used to merge multiple streams together, append more coded symbol from another session, +/// or extract coded symbols from the stream for decoding. +#[derive(Clone, PartialEq, Eq)] +pub struct EncodingSession> { + /// The hashing functions used for mapping values to indices. + pub(crate) hasher: H, + /// The range of the rateless stream which are encoded by this session. + /// This way it is possible to just encode a subset if needed. + pub(crate) range: Range, + /// The coded symbols for the range + pub(crate) coded_symbols: Vec>, + /// Starting at this point, the stream is represented by a hierarchy! + /// We use a somewhat unique representation where coded symbols from 0..split are represented + /// as a "normal" invertible bloom filter table and subsequent coded symbols are represented + /// in a hierarchical way. + /// The nice property of this representation is that we can switch back and forth between the two. + /// This is useful, since certain operations are faster in one representation than the other. + /// + /// The hierarchical representation can be thought of as a rateless set reconciliation stream. + pub(crate) split: usize, +} + +impl> EncodingSession { + /// Create a new encoding session with a given seed and range. + pub fn new(state: H, range: Range) -> Self { + EncodingSession { + hasher: state, + coded_symbols: vec![CodedSymbol::default(); range.len()], + split: range.end, // We start with a non-hierarchical stream. + range, + } + } + + /// Create a EncodingSession from a vector of coded symbols. + /// + /// Panics if the split is out of range or if the length of te vector + /// and the length of the range differ. + pub fn from_coded_symbols( + state: H, + coded_symbols: Vec>, + range: Range, + split: usize, + ) -> Self { + assert!(split >= range.start && split <= range.end); + assert_eq!(coded_symbols.len(), range.len()); + EncodingSession { + hasher: state, + coded_symbols, + split, + range, + } + } + + /// Create a EncodingSession from a vector of coded symbols. + /// + /// Returns an error if the split is out of range or if the length of te vector + /// and the length of the range differ. + pub fn try_from_coded_symbols( + state: H, + coded_symbols: Vec>, + range: Range, + split: usize, + ) -> Result { + if split < range.start || split > range.end { + return Err(SetReconciliationError::SplitOutOfRange); + } + if coded_symbols.len() > range.len() { + return Err(SetReconciliationError::RangeLengthMismatch); + } + Ok(EncodingSession { + hasher: state, + coded_symbols, + split, + range, + }) + } + + /// Adds an entity to the encoding session. + pub fn insert(&mut self, entity: T) { + let check_hash = CodedSymbol::new(&self.hasher, entity, false); + self.add_entity_inner(&check_hash, false); + } + + /// Adds multiple entities to the encoding session. + pub fn extend(&mut self, entities: impl Iterator) { + for entity in entities { + self.insert(entity); + } + } + + /// Returns the encoded rateless stream. + /// Don't forget to either move the split point to the desired place or communicate it + /// with the receiver of this data! Otherwise, the stream cannot be processed correctly! + pub fn into_coded_symbols(self) -> impl Iterator> { + self.coded_symbols.into_iter() + } + + fn append_unchecked(&mut self, mut other: EncodingSession) { + other.move_split_point(self.range.end); + self.coded_symbols.append(&mut other.coded_symbols); + self.range.end = other.range.end; + } + + /// Appends another encoded stream to this session. + /// The function will automatically adapt the split point of the second stream, so that + /// it is compatible with the first one. + pub fn append(&mut self, other: EncodingSession) { + assert_eq!(self.hasher, other.hasher); + assert_eq!(self.range.end, other.range.start); + self.append_unchecked(other); + } + + /// Attempt to append another encoding session onto this one returning an error + /// if the hashers do not match or if the ranges are not contiguous. + pub fn try_append( + &mut self, + other: EncodingSession, + ) -> Result<(), SetReconciliationError> { + if self.hasher != other.hasher { + return Err(SetReconciliationError::MismatchedHasher); + } + if self.range.end != other.range.start { + return Err(SetReconciliationError::NonContiguousRanges); + } + self.append_unchecked(other); + Ok(()) + } + + /// Call this function to extract the next `n` many coded symbols from the current session. + /// Note: this will move the split point, such that the next extraction will also be fast. + /// Inserting elements will however become slower if the split point is not moved to the end again! + pub fn split_off(&mut self, n: usize) -> EncodingSession { + let split = (self.range.start + n).min(self.range.end); + assert!( + split > self.range.start, + "split {split} must be greater than start {}", + self.range.start + ); + if split < self.split { + self.move_split_point(split); + } + let mut rest = EncodingSession { + hasher: self.hasher, + range: split..self.range.end, + coded_symbols: self.coded_symbols.split_off(split - self.range.start), + split, + }; + self.range.end = split; + std::mem::swap(self, &mut rest); + rest + } + + fn merge_unchecked(mut self, other: EncodingSession, negated: bool) -> Self { + self.coded_symbols + .iter_mut() + .zip(other.coded_symbols) + .for_each(|(a, b)| a.add(&b, negated)); + + self + } + + /// Merge another encoding session representing the same range into this one. + /// This is needed in case of sharding or parallel processing. + /// It should also be used to combine the data from two parties in order to determine + /// the symmetric difference between their sets. + /// + /// The `negated` parameter indicates whether the values in the other session should be negated. + pub fn merge(self, other: EncodingSession, negated: bool) -> Self { + assert_eq!(self.range, other.range); + assert_eq!(self.hasher, other.hasher); + self.merge_unchecked(other, negated) + } + + /// Attempt to merge an encoding session into this one. If the hashers or ranges differ then + /// this will fail with an error result. + pub fn try_merge( + self, + other: EncodingSession, + negated: bool, + ) -> Result { + if self.hasher != other.hasher { + return Err(SetReconciliationError::MismatchedHasher); + } + if self.range != other.range { + return Err(SetReconciliationError::MismatchedRanges); + } + Ok(self.merge_unchecked(other, negated)) + } + + /// Helper function which adds an entity to all the indices determined by the hash functions. + /// It also works, when the stream is represented partially or fully hierarchically! + /// Calls a functor for each changed position which might now represent a single entity. + /// Counts how many elements changed to zero/non-zero. + pub(crate) fn add_to_stream( + &mut self, + entity: &CodedSymbol, + negated: bool, + range: Range, + mut f: impl FnMut(CodedSymbol, usize), + ) -> (isize, usize) { + let mut changes = 0; + let mut required_bits = 0; + for mut i in indices(&self.hasher, &entity.value, self.range.end) { + while i >= self.split && i >= self.range.start && i > 0 { + self.coded_symbols[i - self.range.start].add(entity, negated); + i = parent(i); + } + if i >= self.range.start { + if self.is_zero(i) { + changes += 1; + } + self.coded_symbols[i - self.range.start].add(entity, negated); + if self.is_zero(i) { + changes -= 1; + } else if range.contains(&i) { + let (is_pure, bits) = self.is_pure(i); + if is_pure { + let tmp = self.coded_symbols[i - self.range.start]; + f(tmp, i); + } else { + required_bits = required_bits.max(bits); + } + } + } + } + (changes, required_bits) + } + + /// Returns true if this is a pure coded symbol. + pub(crate) fn is_pure(&self, i: usize) -> (bool, usize) { + self.coded_symbols[i - self.range.start].is_pure(&self.hasher, i, self.split) + } + + /// Returns true if no value is present in this coded symbol. + pub(crate) fn is_zero(&self, i: usize) -> bool { + self.coded_symbols[i - self.range.start].is_zero() + } + + /// The caller has to ensure that the same seed was used to construct the entity! + pub(crate) fn add_entity_inner(&mut self, entity: &CodedSymbol, negated: bool) { + self.add_to_stream(entity, negated, 0..0, |_, _| {}); + } + + /// Helper function to move the split point to a desired position. + /// For fast insertion operations, the split point should be at the end of the represented range. + /// For fast extraction operations, the split point should be at the beginning. + pub(crate) fn move_split_point(&mut self, new_split: usize) { + assert!(new_split <= self.range.end && new_split >= self.range.start); + assert!( + self.split <= self.range.end && self.split >= self.range.start, + "{} {:?}", + self.split, + self.range + ); + while self.split < new_split { + if self.split > 0 { + let i = parent(self.split); + if i >= self.range.start { + let tmp = self.coded_symbols[self.split - self.range.start]; + self.coded_symbols[i - self.range.start].add(&tmp, true); + } + } + self.split += 1; + } + while self.split > new_split { + self.split -= 1; + if self.split > 0 { + let i = parent(self.split); + if i >= self.range.start { + let tmp = self.coded_symbols[self.split - self.range.start]; + self.coded_symbols[i - self.range.start].add(&tmp, false); + } + } + } + } +} diff --git a/crates/hriblt/src/error.rs b/crates/hriblt/src/error.rs new file mode 100644 index 0000000..a36570d --- /dev/null +++ b/crates/hriblt/src/error.rs @@ -0,0 +1,22 @@ +/// Errors raised during set reconciliation +#[derive(thiserror::Error, Debug)] +pub enum SetReconciliationError { + /// Expected hashers to match. + #[error("coded symbol hasher mismatched")] + MismatchedHasher, + /// The provided split does not lie within the provided range + #[error("split does not lie within the provided range")] + SplitOutOfRange, + /// Expected a provided range to follow on from the current range. + #[error("provided coded symbol range did not follow on from previous range")] + NonContiguousRanges, + /// Expected ranges to be the same. + #[error("provided coded symbol range did not match the previous range")] + MismatchedRanges, + /// The range of the provided coded symbols did not begin at zero. + #[error("provided coded symbol range did not start from zero")] + NotInitialRange, + /// The length of the range and the length of the coded symbols do not match. + #[error("number of coded symbols did not match the length of the provided range")] + RangeLengthMismatch, +} diff --git a/crates/hriblt/src/lib.rs b/crates/hriblt/src/lib.rs new file mode 100644 index 0000000..0616a74 --- /dev/null +++ b/crates/hriblt/src/lib.rs @@ -0,0 +1,400 @@ +//! This module implements a set reconciliation algorithm using XOR-based hashes. +//! +//! The core algorithm is based on the idea of set similarity sketching where pure hashes are identified +//! by testing whether one of the 5 hash functions would map the candidate value back to the index +//! of the value. Taking advantage of this necessary condition reduces the number of necessary checksum +//! bits by a bit. +//! +//! To make this algorithm rateless, we simply observe that any given IBLT becomes another IBLT if +//! we XOR the hashes of the upper half of the hashes with the lower half. +//! This process can also be realized by mapping one code symbol at a time into the lower half, such +//! that we can generate ANY number of coded symbols. Since this procedure is revertable when the next coded symbol +//! is provided by the client, one ends up with a rateless set reconciliation algorithm. +//! +//! The decoding algorithm essentially reconstructs in each iteration an IBLT with one more coded symbol +//! and then tries to decode the two coded symbols which have been modified by the expansion operation. +//! +//! This algorithm has similar properties to the "Practical Rateless Set Reconciliation" algorithm. +//! Main differences are: +//! * We only use 5 hash functions instead of log(n). +//! * As a result we only require 5 independent hash functions instead of log(n) many. +//! * The amount of data being transferred is comparable to the one in the paper. +//! * The chance that two documents collide on all hash functions is higher, but still very low, +//! since we utilize 5 hash functions instead of just 3. +//! * There is no complicated math involved. In the paper it is important that the exact same computation +//! is performed by both sides or the scheme will fall apart. (I.e. any kind of math optimizations must be disabled +//! and a stable math library must be used!) +//! * Encoding/decoding is faster due to the fixed number of hash functions and the simpler operations. +//! * Since we have a fixed number of hash functions, we can utilize the coded symbol index as +//! an additional condition. In fact, we need to compute just a single hash function (on average). +mod coded_symbol; +mod decoded_value; +mod decoding_session; +mod encoding_session; +mod error; + +use std::{ + fmt::Debug, + hash::{DefaultHasher, Hash, Hasher}, + ops::BitXorAssign, +}; + +pub use coded_symbol::CodedSymbol; +pub use decoded_value::DecodedValue; +pub use decoding_session::DecodingSession; +pub use encoding_session::EncodingSession; +pub use error::SetReconciliationError; + +/// Computes independent hash functions. +pub trait HashFunctions: Eq + Copy + Debug { + /// Hashes the given value with the n-th hash function. + /// This trait should provide 5 independent hash functions! + fn hash(&self, value: &T, n: u32) -> u32; + /// Computes a checksum. Note this checksum must become invalid + /// under xor operations! + fn check_sum(&self, value: &T) -> u64; +} + +/// Hasher builder implementing equality operation of seed value. +#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)] +pub struct DefaultHashFunctions; + +impl HashFunctions for DefaultHashFunctions { + fn hash(&self, value: &T, n: u32) -> u32 { + let mut hasher = DefaultHasher::new(); + n.hash(&mut hasher); + value.hash(&mut hasher); + hasher.finish() as u32 + } + + fn check_sum(&self, value: &T) -> u64 { + let mut hasher = DefaultHasher::new(); + value.hash(&mut hasher); + hasher.finish() + } +} + +/// Trait for value types that can be used in the set reconciliation algorithm. +pub trait Encodable: Copy + Eq + PartialEq + Hash { + /// Returns a zero value for this type which is usually the default value. + fn zero() -> Self; + /// Xor the current value with another value of the same type. + /// This must not strictly be an XOR operation. We only require that applying the operation twice + /// returns the original value. + fn xor(&mut self, other: Self); +} + +impl Encodable for T { + fn zero() -> Self { + Self::default() + } + + fn xor(&mut self, other: Self) { + *self ^= other; + } +} + +fn indices( + builder: &impl HashFunctions, + value: &T, + stream_len: usize, +) -> impl Iterator { + (0..5).map(move |seed| index_for_seed(builder, value, stream_len, seed)) +} + +/// This function computes with 5 distinct hash functions 5 indices to which a value maps. +/// Essentially, we are "fighting" here two contradicting requirements: +/// - More hash functions with larger partitions reduce the probability that two values maps +/// to exactly the same indices for all hash functions! In this situation, we can decode the stream. +/// - Fewer (ideally 3) hash functions with larger partitions lead to a higher chance to +/// find a pure value in the stream, i.e. the stream can be decoded with fewer coded symbols. +/// +/// After testing various schemes, I settled for this one which uses 4 equally sized partitions, +/// one for each of the first 4 hash functions. This ensures that the first 4 hash functions +/// map to distinct indices. +/// The last hash function is used to reduce the probability of hash collisions further without +/// reducing the chance to find pure values in the stream. +/// +/// Note: we want an odd number of hash functions, so that collapsing the stream to a single coded symbol +/// (or small number of coded symbols) won't erase the value information. +/// +/// The second return value indicates whether the entry should be stored negated. +fn index_for_seed( + builder: &impl HashFunctions, + value: &T, + stream_len: usize, + seed: u32, +) -> usize { + let mut hash = builder.hash(value, seed); + let mask = 31; + let mut lsb = hash & mask; + hash -= lsb; + if seed == 4 { + lsb = 0; + } else { + lsb &= !3; + lsb += seed; + } + hash += lsb; + hash_to_index(hash, stream_len) +} + +/// Determines the parent index in the rateless/hierarchical representation. +fn parent(i: usize) -> usize { + i - ((i + 1).next_power_of_two() / 2) +} + +/// Function to map a hash value into a correct index for a given number of coded symbols. +/// This function is compatible with the above `parent` function in the sense that +/// repeatedly applying `parent` until the index is less than `n` will yield the same result! +fn hash_to_index(hash: u32, n: usize) -> usize { + let power_of_two = (n as u32).next_power_of_two(); + let hash = hash % power_of_two; + let res = if hash >= n as u32 { + hash - power_of_two / 2 + } else { + hash + }; + res as usize +} + +#[cfg(test)] +mod tests { + use std::{collections::HashMap, fmt::Debug, time::Instant}; + + use crate::{ + DefaultHashFunctions, EncodingSession, decoded_value::DecodedValue, + decoding_session::DecodingSession, hash_to_index, parent, + }; + + /// This test ensures that the parent and hash_to_index functions are consistent to each other! + #[test] + fn test_parent() { + for i in 0..1000 { + let mut ii = i; + while ii > 0 { + let jj = parent(ii); + for k in jj + 1..=ii { + assert_eq!(hash_to_index(i as u32, k), jj, "{i} {ii} {k}"); + } + assert_eq!(hash_to_index(i as u32, jj + 1), jj, "{i} {ii} {jj}"); + ii = jj; + } + } + } + + /// Test that moving the split point works correctly. + /// This test simply goes through all possible size and split point combinations and compares + /// the results when the split point is changed before or after inserting elements. + /// In both cases, the result should be the same! + #[test] + fn test_move_split() { + let state = DefaultHashFunctions; + for n in 1..64 { + for s in 0..=n { + let mut encoding1 = EncodingSession::new(state, 0..n); + let mut encoding2 = EncodingSession::new(state, 0..n); + encoding2.move_split_point(s); + for k in 1..100 { + encoding1.insert(k); + encoding2.insert(k); + } + encoding1.move_split_point(s); + assert_eq!( + encoding1.coded_symbols, encoding2.coded_symbols, + "n: {n}, s: {s}" + ); + } + } + } + + /// Test encoding and decoding of a large stream. + #[test] + fn test_single_stream() { + let mut stats = Stats::default(); + let mut bits = Stats::default(); + let mut encoding_time = Stats::default(); + let mut decoding_time = Stats::default(); + let mut deocding_time_fast = Stats::default(); + for i in 0..10 { + let items = 100000; + let entries: Vec<_> = (1u64..=items).collect(); + let state = DefaultHashFunctions; + let start = Instant::now(); + let mut stream1 = EncodingSession::new(state, 0..items as usize * 15 / 10); + stream1.extend(entries.iter().cloned()); + encoding_time.add(start.elapsed().as_secs_f32()); + + let start = Instant::now(); + let mut decoding_session = DecodingSession::new(state); + decoding_session.append(stream1.clone()); + assert!( + decoding_session.is_done(), + "{} {i}", + decoding_session.non_zero, + ); + stats.add(decoding_session.consumed_coded_symbols() as f32); + bits.add(decoding_session.required_bits as f32); + decoding_time.add(start.elapsed().as_secs_f32()); + let mut decoded: Vec<_> = decoding_session + .into_decoded_iter() + .map(|decoded_value| { + let DecodedValue::Addition(e) = decoded_value else { + panic!("Value was deleted, but expected added"); + }; + e + }) + .collect(); + decoded.sort(); + assert_eq!(decoded.len(), items as usize); + assert_eq!(decoded, entries); + + let start = Instant::now(); + let decoding_session = DecodingSession::from_encoding(stream1); + assert!(decoding_session.is_done()); + deocding_time_fast.add(start.elapsed().as_secs_f32()); + let decoded2: Vec<_> = decoding_session.into_decoded_iter().collect(); + assert_eq!(decoded2.len(), items as usize); + } + println!("stream size: {stats:?}"); + println!("required bits: {bits:?}"); + println!("encoding time: {encoding_time:?}"); + println!("decoding time: {decoding_time:?}"); + println!("decoding time fast: {deocding_time_fast:?}"); + } + + /// Test that splitting an encoding session and reassembling it into a decoding session works. + /// The comparison must be done in the hierarchical representation which is enforced by + /// calling move_split_point. + /// Note: we abort the loop, once the stream was successfully decoded, since otherwise some + /// assertion would trigger :) + #[test] + fn test_splitting_of_decoding() { + let state = DefaultHashFunctions; + let mut stream1 = EncodingSession::new(state, 0..200); + let items = 100; + stream1.extend(1..=items); + + // Test that decoding would actually work... + let mut decoding_session = DecodingSession::new(state); + decoding_session.append(stream1.clone()); + assert!(decoding_session.is_done()); + + let mut expected = stream1.clone(); + expected.move_split_point(0); + let expected: Vec<_> = expected.into_coded_symbols().collect(); + let mut decoding_session = DecodingSession::new(state); + for i in 0.. { + let mut got = stream1.split_off(10); + decoding_session.append(got.clone()); + assert_eq!(got.range.start, i * 10); + got.move_split_point(i * 10); + let got: Vec<_> = got.into_coded_symbols().collect(); + assert_eq!(got, expected[i * 10..(i + 1) * 10]); + if decoding_session.is_done() { + break; + } + } + assert_eq!(decoding_session.into_decoded_iter().count(), items); + } + + #[derive(Default)] + struct Stats { + sum: f32, + sum2: f32, + cnt: f32, + max: f32, + } + + impl Stats { + fn add(&mut self, v: f32) { + self.sum += v; + self.sum2 += v * v; + self.cnt += 1.0; + if v > self.max { + self.max = v; + } + } + + fn finish(&self) -> (f32, f32, f32) { + let mean = self.sum / self.cnt; + let var = self.sum2 / self.cnt - mean * mean; + (mean, var.max(0.0).sqrt() / mean, self.max) + } + } + + impl Debug for Stats { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let (mean, stddev, max) = self.finish(); + write!(f, "{mean},{stddev},{max}") + } + } + + #[test] + fn test_merging() { + let state = DefaultHashFunctions; + let mut stream1 = EncodingSession::new(state, 0..200); + stream1.extend(0..20); + let mut stream2 = EncodingSession::new(state, 0..200); + stream2.extend(10..30); + let merged = stream1.merge(stream2, true); + let decoding_session = DecodingSession::from_encoding(merged); + assert!(decoding_session.is_done()); + let mut decoded: Vec<_> = decoding_session.into_decoded_iter().collect(); + decoded.sort(); + assert_eq!( + &decoded[0..10], + (0..10).map(DecodedValue::Addition).collect::>() + ); + assert_eq!( + &decoded[10..20], + (20..30).map(DecodedValue::Deletion).collect::>() + ); + } + + #[test] + fn test_statistics() { + let state = DefaultHashFunctions; + let mut stats = HashMap::new(); + + for start in 0..100 { + let mut stream = EncodingSession::new(state, 0..1500); + stream.move_split_point(0); + for value in 1u64..1000 { + stream.insert(value); + if ((value as f32).log2() * 8.0).floor() + != ((value as f32 + 1.0).log2() * 8.0).floor() + { + let mut decoding_session = DecodingSession::new(state); + decoding_session.append(stream.clone()); + assert!(decoding_session.is_done(), "start: {start}, value: {value}"); + { + // It is in theory possible that the fast decoding requires a longer stream than the + // incremental decoding. This can happen when collisions cancel out in the incremental decoding + // case. This test shows that this is extremely unlikely to happen. + let decoding_session = DecodingSession::from_encoding( + stream + .clone() + .split_off(decoding_session.consumed_coded_symbols()), + ); + assert!(decoding_session.is_done(), "start: {start}, value: {value}"); + } + let s = stats + .entry(value) + .or_insert((Stats::default(), Stats::default())); + s.0.add(decoding_session.consumed_coded_symbols() as f32); + s.1.add(decoding_session.required_bits as f32); + } + } + } + let mut stats: Vec<_> = stats.into_iter().collect(); + stats.sort_by_key(|(value, _)| *value); + for (value, (stat, bits)) in stats { + println!("{value},{stat:?},{bits:?}"); + } + } +} + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDocTests; From 39c65cc265754d4933734e9b097cb1f0d791a4c0 Mon Sep 17 00:00:00 2001 From: Sam Cutler Date: Mon, 19 Jan 2026 13:56:40 +0000 Subject: [PATCH 2/4] Add evaluation code --- crates/hriblt/Cargo.toml | 11 + crates/hriblt/docs/hashing_functions.md | 2 +- crates/hriblt/evaluation/bench.rs | 303 +++++++++++++++++++++++ crates/hriblt/evaluation/plot-overhead.r | 116 +++++++++ crates/hriblt/src/encoding_session.rs | 2 +- 5 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 crates/hriblt/evaluation/bench.rs create mode 100755 crates/hriblt/evaluation/plot-overhead.r diff --git a/crates/hriblt/Cargo.toml b/crates/hriblt/Cargo.toml index 91f8585..4084a42 100644 --- a/crates/hriblt/Cargo.toml +++ b/crates/hriblt/Cargo.toml @@ -10,3 +10,14 @@ categories = ["algorithms", "data-structures", "mathematics", "science"] [dependencies] thiserror = "2" +clap = { version = "4", features = ["derive"], optional = true } +rand = { version = "0.9", optional = true } + +[[bin]] +name = "hriblt-bench" +path = "evaluation/bench.rs" +required-features = ["bin"] + +[features] +default = [] +bin = ["dep:clap", "dep:rand"] diff --git a/crates/hriblt/docs/hashing_functions.md b/crates/hriblt/docs/hashing_functions.md index 8bede64..884166a 100644 --- a/crates/hriblt/docs/hashing_functions.md +++ b/crates/hriblt/docs/hashing_functions.md @@ -8,7 +8,7 @@ The following documentation provides more details on this trait in particular. H When using HRIBLT in production systems it is important to consider the stability of your hash functions. -We provide a `DefaultHashFunctions` type which is a wrapper around the `DefaultHasher` type provided by the Rust standard library. Though the seed for this function is fixed, it should be noted that the hashes produces by this type are *not* guarenteed to be stable across different versions of the Rust standard library. As such, you should not use this type for any situation where clients might potentially be running on a binary built with an unspecified version of Rust. +We provide a `DefaultHashFunctions` type which is a wrapper around the `DefaultHasher` type provided by the Rust standard library. Though the seed for this function is fixed, it should be noted that the hashes produces by this type are *not* guaranteed to be stable across different versions of the Rust standard library. As such, you should not use this type for any situation where clients might potentially be running on a binary built with an unspecified version of Rust. We recommend you implement your own `HashFunctions` implementation with a stable hash function. diff --git a/crates/hriblt/evaluation/bench.rs b/crates/hriblt/evaluation/bench.rs new file mode 100644 index 0000000..bae850e --- /dev/null +++ b/crates/hriblt/evaluation/bench.rs @@ -0,0 +1,303 @@ +//! Benchmarking tool for hriblt set reconciliation. +//! +//! This tool runs trials to measure the success rate of decoding set differences. + +use std::{collections::HashSet, ops::Range, str::FromStr}; + +use clap::{Parser, ValueEnum}; +use rand::prelude::*; + +use hriblt::{DecodedValue, DecodingSession, DefaultHashFunctions, EncodingSession}; + +/// A diff size specification that can be a single value or a range. +#[derive(Debug, Clone)] +struct DiffSizeSpec { + range: Range, +} + +impl FromStr for DiffSizeSpec { + type Err = String; + + fn from_str(s: &str) -> Result { + // Try parsing as a range first (e.g., "1..10" or "1..=10") + if let Some((start, end)) = s.split_once("..=") { + let start: u32 = start.parse().map_err(|_| format!("invalid range start: {}", start))?; + let end: u32 = end.parse().map_err(|_| format!("invalid range end: {}", end))?; + if start > end { + return Err(format!("range start {} must be <= end {}", start, end)); + } + return Ok(DiffSizeSpec { range: start..end + 1 }); + } + if let Some((start, end)) = s.split_once("..") { + let start: u32 = start.parse().map_err(|_| format!("invalid range start: {}", start))?; + let end: u32 = end.parse().map_err(|_| format!("invalid range end: {}", end))?; + if start >= end { + return Err(format!("range start {} must be < end {}", start, end)); + } + return Ok(DiffSizeSpec { range: start..end }); + } + // Otherwise parse as a single value + let val: u32 = s.parse().map_err(|_| format!("invalid diff size: {}", s))?; + Ok(DiffSizeSpec { range: val..val + 1 }) + } +} + +/// How to iterate through the diff size range. +#[derive(Debug, Clone, Copy, Default, ValueEnum)] +enum DiffSizeMode { + /// Pick a random value from the range for each trial + #[default] + Random, + /// Iterate through the range incrementally, looping if needed + Incremental, +} + +/// Iterator over diff sizes based on the mode. +enum DiffSizeIter { + Random { + range: Range, + }, + Incremental { + range: Range, + current: u32, + }, +} + +impl DiffSizeIter { + fn new(spec: &DiffSizeSpec, mode: DiffSizeMode) -> Self { + match mode { + DiffSizeMode::Random => DiffSizeIter::Random { + range: spec.range.clone(), + }, + DiffSizeMode::Incremental => DiffSizeIter::Incremental { + range: spec.range.clone(), + current: spec.range.start, + }, + } + } + + fn next_diff_size(&mut self, rng: &mut R) -> u32 { + match self { + DiffSizeIter::Random { range } => rng.random_range(range.clone()), + DiffSizeIter::Incremental { range, current } => { + let val = *current; + *current += 1; + if *current >= range.end { + *current = range.start; + } + val + } + } + } +} + +#[derive(Parser, Debug)] +#[command(name = "hriblt-bench")] +#[command(about = "Run reconciliation trials to measure decoding success rate")] +struct Args { + /// Number of trials to run + #[arg(short, long, default_value_t = 100)] + trials: u32, + + /// Size of each set (number of elements) + #[arg(short, long, default_value_t = 1000)] + set_size: u32, + + /// Number of differences between the sets (single value or range like "1..10" or "1..=10") + #[arg(short, long, default_value = "10")] + diff_size: DiffSizeSpec, + + /// How to select diff sizes from a range + #[arg(long, value_enum, default_value_t = DiffSizeMode::Random)] + diff_mode: DiffSizeMode, + + /// Multiplier for max symbols to try (max_symbols = diff_size * multiplier) + #[arg(short, long, default_value_t = 10)] + multiplier: u32, + + /// Random seed (optional, for reproducibility) + #[arg(long)] + seed: Option, + + /// Print each trial as a TSV row to stdout + #[arg(long)] + tsv: bool, +} + +/// Result of a single trial +struct TrialResult { + success: bool, + coded_symbols: Option, +} + +fn run_trial( + rng: &mut R, + set_size: u32, + diff_size: u32, + max_symbols: usize, +) -> TrialResult { + // Ensure we have at least 32 symbols to work with + let max_symbols = max_symbols.max(32); + + // Generate base set of random u64 values + let base_set: HashSet = (0..set_size).map(|_| rng.random()).collect(); + + // Create set A as the base set + let set_a: Vec = base_set.iter().copied().collect(); + + // Create set B by removing some elements and adding new ones + let mut set_b: HashSet = base_set.clone(); + + // Remove diff_size/2 elements from set B + let removals = diff_size / 2; + let additions = diff_size - removals; + + let mut to_remove: Vec = set_b.iter().copied().collect(); + to_remove.shuffle(rng); + for val in to_remove.into_iter().take(removals as usize) { + set_b.remove(&val); + } + + // Add diff_size - removals new elements to set B + for _ in 0..additions { + loop { + let new_val: u64 = rng.random(); + if !base_set.contains(&new_val) && set_b.insert(new_val) { + break; + } + } + } + + let set_b: Vec = set_b.into_iter().collect(); + + // Create encoding sessions for both sets with max capacity + let state = DefaultHashFunctions; + + let mut encoder_a = EncodingSession::new(state, 0..max_symbols); + encoder_a.extend(set_a.iter().copied()); + + let mut encoder_b = EncodingSession::new(state, 0..max_symbols); + encoder_b.extend(set_b.iter().copied()); + + // Merge the two encodings (negated to get the difference) + let mut merged = encoder_a.merge(encoder_b, true); + + // Start with 1x the diff size, grow by 10% until success or max + let mut current_symbols = (diff_size as usize).max(1); + let mut decoding_session = DecodingSession::new(state); + + while current_symbols <= max_symbols { + // Split off symbols up to current_symbols + let chunk_start = decoding_session.consumed_coded_symbols(); + let chunk_end = current_symbols.min(max_symbols); + + if chunk_end > chunk_start { + let chunk = merged.split_off(chunk_end - chunk_start); + decoding_session.append(chunk); + } + + if decoding_session.is_done() { + let coded_symbols = decoding_session.consumed_coded_symbols(); + // Verify the decoded difference matches expected + let decoded: HashSet<_> = decoding_session + .into_decoded_iter() + .map(|v| match v { + DecodedValue::Addition(x) | DecodedValue::Deletion(x) => x, + }) + .collect(); + + return TrialResult { + success: decoded.len() == diff_size as usize, + coded_symbols: Some(coded_symbols), + }; + } + + // Grow by 10%, but at least 1 + let growth = (current_symbols / 10).max(1); + current_symbols += growth; + } + + TrialResult { + success: false, + coded_symbols: None, + } +} + +fn main() { + let args = Args::parse(); + + let mut rng: Box = match args.seed { + Some(seed) => Box::new(StdRng::seed_from_u64(seed)), + None => Box::new(rand::rng()), + }; + + let is_range = args.diff_size.range.end - args.diff_size.range.start > 1; + let range_desc = if is_range { + format!("{}..{}", args.diff_size.range.start, args.diff_size.range.end) + } else { + format!("{}", args.diff_size.range.start) + }; + + eprintln!("Running {} trials...", args.trials); + eprintln!(" Set size: {}", args.set_size); + eprintln!(" Diff size: {} ({:?})", range_desc, args.diff_mode); + eprintln!(" Max symbols multiplier: {}x", args.multiplier); + eprintln!(); + + if args.tsv { + println!("trial\tset_size\tdiff_size\tsuccess\tcoded_symbols\toverhead"); + } + + let mut diff_iter = DiffSizeIter::new(&args.diff_size, args.diff_mode); + + let mut successes = 0; + let mut failures = 0; + + for i in 0..args.trials { + let diff_size = diff_iter.next_diff_size(&mut *rng); + let max_symbols = (diff_size * args.multiplier) as usize; + let result = run_trial(&mut *rng, args.set_size, diff_size, max_symbols); + + if args.tsv { + let coded_symbols_str = result + .coded_symbols + .map(|n| n.to_string()) + .unwrap_or_default(); + let overhead_str = result + .coded_symbols + .map(|n| { + if diff_size > 0 { + format!("{:.2}", n as f64 / diff_size as f64) + } else { + String::new() + } + }) + .unwrap_or_default(); + println!( + "{}\t{}\t{}\t{}\t{}\t{}", + i + 1, + args.set_size, + diff_size, + result.success, + coded_symbols_str, + overhead_str + ); + } + + if result.success { + successes += 1; + } else { + failures += 1; + if !args.tsv && failures <= 5 { + eprintln!("Trial {} failed (diff_size={})", i + 1, diff_size); + } + } + } + + eprintln!(); + eprintln!("Results:"); + eprintln!(" Successes: {}/{} ({:.1}%)", successes, args.trials, + 100.0 * successes as f64 / args.trials as f64); + eprintln!(" Failures: {}/{} ({:.1}%)", failures, args.trials, + 100.0 * failures as f64 / args.trials as f64); +} diff --git a/crates/hriblt/evaluation/plot-overhead.r b/crates/hriblt/evaluation/plot-overhead.r new file mode 100755 index 0000000..da50206 --- /dev/null +++ b/crates/hriblt/evaluation/plot-overhead.r @@ -0,0 +1,116 @@ +#!/usr/bin/env Rscript + +## Plot overhead percentiles from hriblt benchmark TSV output. +## +## Usage: plot-overhead.r [input.tsv] [output.pdf] +## +## The input TSV should have columns: trial, set_size, diff_size, success, coded_symbols, overhead +## Generated by: cargo run -p hriblt --bin hriblt-bench --features bin -- --tsv ... + +library(dplyr) +library(ggplot2) +library(readr) +library(stringr) + +args <- commandArgs(trailingOnly = TRUE) +input <- "overhead.tsv" +output <- NULL + +if (length(args) > 0) { + if (args[1] %in% c("-h", "--help")) { + cat(" +Usage: plot-overhead.r [input.tsv] [output.pdf] + + Plot overhead percentiles (p0, p25, p50, p75, p99) vs diff_size from benchmark TSV. + + The input TSV should be generated by hriblt-bench with --tsv flag: + + cargo run -p hriblt --bin hriblt-bench --features bin -- \\ + --trials 1000 --diff-size '1..101' --diff-mode incremental --tsv > overhead.tsv + + Example usage: + + plot-overhead.r overhead.tsv overhead.pdf + +") + quit(status = 0) + } + input <- args[1] +} + +if (length(args) > 1) { + output <- args[2] +} else { + output <- str_replace(input, "\\.(tsv|csv)$", ".pdf") + if (output == input) { + output <- paste0(input, ".pdf") + } +} + +# Read data +data <- read_tsv(input, show_col_types = FALSE) + +# Filter to successful trials with valid overhead +data <- data %>% + filter(success == TRUE, !is.na(overhead), overhead > 0) + +# Compute percentiles per diff_size +stats <- data %>% + group_by(diff_size) %>% + summarise( + p0 = min(overhead), + p25 = quantile(overhead, 0.25), + p50 = quantile(overhead, 0.50), + p75 = quantile(overhead, 0.75), + p99 = quantile(overhead, 0.99), + n = n(), + .groups = "drop" + ) + +# Get sample size for title +total_n <- nrow(data) +trials_per_diff <- stats$n[1] + +# Create the plot +plot <- ggplot(stats, aes(x = diff_size)) + + # p0-p99 range (min-max) + geom_ribbon(aes(ymin = p0, ymax = p99), fill = "#cccccc", alpha = 0.5) + + # p25-p75 range (interquartile) + geom_ribbon(aes(ymin = p25, ymax = p75), fill = "#6699cc", alpha = 0.7) + + # p50 median line + geom_line(aes(y = p50), color = "#003366", linewidth = 1) + + # Reference line at y=1 (theoretical minimum) + geom_hline(yintercept = 1, linetype = "dashed", color = "#999999", alpha = 0.7) + + # Labels + labs( + title = paste0("Overhead vs Diff Size (n = ", trials_per_diff, " trials per diff_size)"), + subtitle = "coded_symbols / diff_size", + x = "Diff Size", + y = "Overhead Multiplier" + ) + + # Theme + + theme_minimal() + + theme( + plot.title = element_text(size = 14, face = "bold"), + plot.subtitle = element_text(size = 10, color = "#666666"), + axis.title = element_text(size = 11), + panel.grid.minor = element_blank() + ) + + # Scales + scale_y_continuous( + breaks = scales::breaks_extended(8), + limits = c(0, NA) + ) + +# Add legend manually via annotation +plot <- plot + + annotate("rect", xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, fill = NA) + + labs(caption = "Gray: p0-p99 range | Blue: p25-p75 range | Line: p50 median") + +# Save to PDF +pdf(file = output, width = 10, height = 6) +print(plot) +dev.off() + +cat(paste0("Output: ", output, "\n")) diff --git a/crates/hriblt/src/encoding_session.rs b/crates/hriblt/src/encoding_session.rs index 69538f3..abebdd4 100644 --- a/crates/hriblt/src/encoding_session.rs +++ b/crates/hriblt/src/encoding_session.rs @@ -61,7 +61,7 @@ impl> EncodingSession { /// Create a EncodingSession from a vector of coded symbols. /// - /// Returns an error if the split is out of range or if the length of te vector + /// Returns an error if the split is out of range or if the length of the vector /// and the length of the range differ. pub fn try_from_coded_symbols( state: H, From f65e2620af0575fb1c9885e4b2e9e6ffd9715dcc Mon Sep 17 00:00:00 2001 From: Sam Cutler Date: Mon, 19 Jan 2026 17:04:40 +0000 Subject: [PATCH 3/4] Add readme and script to generate plots --- crates/hriblt/docs/sizing.md | 2 +- crates/hriblt/evaluation/README.md | 78 ++++++++++++++++++ .../hriblt/evaluation/overhead/overhead.png | Bin 0 -> 200593 bytes crates/hriblt/scripts/generate-overhead-plots | 39 +++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 crates/hriblt/evaluation/README.md create mode 100644 crates/hriblt/evaluation/overhead/overhead.png create mode 100755 crates/hriblt/scripts/generate-overhead-plots diff --git a/crates/hriblt/docs/sizing.md b/crates/hriblt/docs/sizing.md index 912f803..1dbc14a 100644 --- a/crates/hriblt/docs/sizing.md +++ b/crates/hriblt/docs/sizing.md @@ -10,7 +10,7 @@ The number of coded symbols required to find the difference between two sets is `y = len(coded_symbols) / diff_size` -![Coded symbol multiplier](./assets/coded-symbol-multiplier.png) +![Coded symbol multiplier](../evaulation/overhead/overhead.png) For small diffs, the number of coded symbols required per value is larger, after a difference of approximately 100 values the coefficient settles on around 1.3 to 1.4. diff --git a/crates/hriblt/evaluation/README.md b/crates/hriblt/evaluation/README.md new file mode 100644 index 0000000..af21d3f --- /dev/null +++ b/crates/hriblt/evaluation/README.md @@ -0,0 +1,78 @@ +# Evaluation + +The crate includes an overhead evaluation to measure the efficiency of the set reconciliation algorithm. +Below are instructions on how to run the evaluation. + +_Note that all of these should be run from the crate's root directory!_ + +## Overhead Evaluation + +The overhead evaluation measures how many coded symbols are required to successfully decode set differences of various sizes. +The key metric is the **overhead multiplier**: the ratio of coded symbols needed to the actual diff size. + +See [overhead results](evaluation/overhead.md) for the predefined configurations. + +### Running the Evaluation + +1. Ensure R and ImageMagick are installed with necessary packages: + + - Install R from [download](https://cran.r-project.org/) or using your platform's package manager. + - Start `R` and install packages by executing `install.packages(c('dplyr', 'ggplot2', 'readr', 'stringr', 'scales'))`. + - Install ImageMagick using the official [instructions](https://imagemagick.org/script/download.php). + - Install Ghostscript for PDF conversion: `brew install ghostscript` (macOS) or `apt install ghostscript` (Linux). + +2. Run the benchmark tool directly to see available options: + + cargo run --release --features bin --bin hriblt-bench -- --help + + Example: run 1000 trials with diff sizes from 1 to 100: + + cargo run --release --features bin --bin hriblt-bench -- \ + --trials 10000 \ + --set-size 1000 \ + --diff-size '1..101' \ + --diff-mode incremental \ + --tsv + +3. To generate a plot from TSV output: + + cargo run --release --features bin --bin hriblt-bench -- \ + --trials 10000 --diff-size '1..101' --diff-mode incremental --tsv > overhead.tsv + + evaluation/plot-overhead.r overhead.tsv overhead.pdf + +### TSV Output Format + +When using `--tsv`, the benchmark outputs tab-separated data with the following columns: + +| Column | Description | +|--------|-------------| +| `trial` | Trial number (1-indexed) | +| `set_size` | Number of elements in each set | +| `diff_size` | Number of differences between sets | +| `success` | Whether decoding succeeded (`true`/`false`) | +| `coded_symbols` | Number of coded symbols needed to decode | +| `overhead` | Ratio of coded_symbols to diff_size | + +### Regenerating Documentation Plots + +To regenerate the plots in the repository, ensure ImageMagick is available, and run: + + scripts/generate-overhead-plots + +_Note that this will always re-run the benchmark!_ + +## Understanding the Results + +The overhead plot shows percentiles of the overhead multiplier across different diff sizes: + +- **Gray region**: Full range (p0 to p99) - min to ~max overhead observed +- **Blue region**: Interquartile range (p25 to p75) - where 50% of trials fall +- **Dark line**: Median (p50) - typical overhead + +A lower overhead means more efficient encoding. An overhead of 1.0x would mean the number of coded symbols exactly equals the diff size (theoretical minimum). + +Typical results show: +- Small diff sizes (1-10) have higher variance and overhead due to the probabilistic nature of the algorithm +- Larger diff sizes (50+) converge to a more stable overhead around 1.3-1.5x +- The algorithm successfully decodes 100% of trials when given up to 10x the diff size in coded symbols diff --git a/crates/hriblt/evaluation/overhead/overhead.png b/crates/hriblt/evaluation/overhead/overhead.png new file mode 100644 index 0000000000000000000000000000000000000000..9dfd6b7b4fe7d3fc682c2faa8e0dae6238673da5 GIT binary patch literal 200593 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⩔XKGQ+&{}syNzOne-K?-l$_!S}nntKO6EVVqC!7 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 Q7W@-2A?bH{f*(Ks7xQB71poj5 literal 0 HcmV?d00001 diff --git a/crates/hriblt/scripts/generate-overhead-plots b/crates/hriblt/scripts/generate-overhead-plots new file mode 100755 index 0000000..d6000d0 --- /dev/null +++ b/crates/hriblt/scripts/generate-overhead-plots @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +## Run overhead evaluation and generate the plots for the documentation. + +set -eu + +cd "$(dirname "$0")/.." + +plots_dir=evaluation/overhead +tmp_dir=$(mktemp -d) +trap "rm -rf $tmp_dir" EXIT + +# Run benchmark with a good range of diff sizes and enough trials for statistical significance +# Performs 100 trials per diff size +cargo run --release --features bin --bin hriblt-bench -- \ + --trials 20000 \ + --set-size 1000 \ + --diff-size '1..=200' \ + --diff-mode incremental \ + --tsv \ + --seed 42 \ + > "$tmp_dir/overhead.tsv" + +# Generate the PDF plot +evaluation/plot-overhead.r "$tmp_dir/overhead.tsv" "$tmp_dir/overhead.pdf" + +# Create output directory +rm -rf "$plots_dir" +mkdir -p "$plots_dir" + +# Convert PDF to PNG for documentation (requires ghostscript for PDF support) +# Use 'magick' for ImageMagick v7+, fall back to 'convert' for older versions +if command -v magick &> /dev/null; then + magick -density 300 "$tmp_dir/overhead.pdf" -resize 1024x1024 -alpha remove -alpha off "$plots_dir/overhead.png" +else + convert -density 300 "$tmp_dir/overhead.pdf" -resize 1024x1024 -alpha remove -alpha off "$plots_dir/overhead.png" +fi + +echo "Generated plots in $plots_dir/" From 497ae06d2c7ee491603ccbd4dfb4fcee2d7faf4c Mon Sep 17 00:00:00 2001 From: Sam Cutler Date: Mon, 19 Jan 2026 17:53:15 +0000 Subject: [PATCH 4/4] Some reworks --- crates/hriblt/README.md | 4 ++-- .../docs/assets/coded-symbol-multiplier.png | Bin 17282 -> 0 bytes crates/hriblt/docs/sizing.md | 2 +- crates/hriblt/src/coded_symbol.rs | 9 +++++---- crates/hriblt/src/decoding_session.rs | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 crates/hriblt/docs/assets/coded-symbol-multiplier.png diff --git a/crates/hriblt/README.md b/crates/hriblt/README.md index 6b93d8b..33de89e 100644 --- a/crates/hriblt/README.md +++ b/crates/hriblt/README.md @@ -11,9 +11,9 @@ Add the library to your `Cargo.toml` file. hriblt = "0.1" ``` -Create two encoding sessions, one containing your data, and another containing the counter-parties data. This counterparty data might have been sent to you over a network for example. +Create two encoding sessions, one containing Alice's data, and another containing Bob's data. Bob's data might have been sent to you over a network for example. -The following example attempts to reconcile the differences between two sets of `u64` integers, and is done from the perspective of "Bob", who has recieved some symbols from "Alice". +The following example attempts to reconcile the differences between two such sets of `u64` integers, and is done from the perspective of "Bob", who has received some symbols from "Alice". ```rust use hriblt::{DecodingSession, EncodingSession, DefaultHashFunctions}; diff --git a/crates/hriblt/docs/assets/coded-symbol-multiplier.png b/crates/hriblt/docs/assets/coded-symbol-multiplier.png deleted file mode 100644 index 84d3b694d848a0b6d4f30a7715425caf757b9253..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17282 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 CodedSymbol { /// Checks whether this coded symbol is pure, i.e., whether it represents a single entity /// A pure coded symbol must satisfy the following conditions: - /// - The 1-bit counter must be 1 or -1 (which are both represented by the bit being set) - /// - The checksum must match the checksum of the value. + /// - The 1-bit counter must be 1 or -1 (which are both represented by the least significant bit being set) + /// - The checksum must match the absolute value of the checksum of the value. + /// The sign (-/+) tells you if it was an insertion or deletion /// - The indices of the value must match the index of this coded symbol. pub(crate) fn is_pure>( &self, @@ -118,10 +119,10 @@ fn indices_contains( if stream_len > 32 && i % 32 != 0 { let seed = i % 4; let j = index_for_seed(state, value, stream_len, seed as u32); - if i == j { 1 } else { 0 } + i32::from(i == j) } else { indices(state, value, stream_len) - .map(|j| if j == i { 1 } else { 0 }) + .map(|j| i32::from(i == j)) .sum() } } diff --git a/crates/hriblt/src/decoding_session.rs b/crates/hriblt/src/decoding_session.rs index 37bfe6e..a235c43 100644 --- a/crates/hriblt/src/decoding_session.rs +++ b/crates/hriblt/src/decoding_session.rs @@ -10,7 +10,7 @@ use crate::{ pub struct DecodingSession> { /// The encoded stream of hashes. /// All recovered coded symbols have been removed from this stream. - /// If decoded failed, then one can simply append more data and continue decoding. + /// If decoded fails, then one can simply append more data and continue decoding. encoded: EncodingSession, /// All the recovered coded symbols. recovered: Vec>,