#![warn(missing_docs)]
pub mod blocking;
pub mod cross_polytope;
pub mod dense_simhash;
pub mod hyperplane;
pub mod lsh;
pub mod minhash;
pub mod multibit;
pub mod simhash;
#[cfg(feature = "store")]
pub mod store;
pub use blocking::{BlockingConfig, MinHashTextLSH};
pub use cross_polytope::CrossPolytopeHasher;
pub use dense_simhash::DenseSimHashLSH;
pub use hyperplane::HyperplaneHasher;
pub use lsh::{LSHIndex, MinHashLSH, SimHashLSH};
pub use minhash::{MinHash, MinHashSignature};
pub use multibit::{MultibitConfig, MultibitLSH};
pub use simhash::{simhash_fingerprint, SimHashFingerprint};
use std::fmt;
use std::hash::Hasher;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
InvalidParam(&'static str),
DimensionMismatch {
expected: usize,
got: usize,
},
EmptyIndex,
NotBuilt,
AddAfterBuild,
NonFiniteInput,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidParam(msg) => write!(f, "invalid parameter: {msg}"),
Error::DimensionMismatch { expected, got } => {
write!(f, "dimension mismatch (expected {expected}, got {got})")
}
Error::EmptyIndex => f.write_str("empty index"),
Error::NotBuilt => f.write_str("index not built"),
Error::AddAfterBuild => f.write_str("cannot add after build"),
Error::NonFiniteInput => f.write_str("input contains non-finite values (NaN or Inf)"),
}
}
}
impl std::error::Error for Error {}
pub(crate) struct Fnv1a64 {
state: u64,
}
impl Fnv1a64 {
pub(crate) fn new() -> Self {
Self {
state: 0xcbf29ce484222325,
}
}
}
impl Hasher for Fnv1a64 {
fn finish(&self) -> u64 {
self.state
}
fn write(&mut self, bytes: &[u8]) {
const PRIME: u64 = 0x00000100000001B3;
for &b in bytes {
self.state ^= b as u64;
self.state = self.state.wrapping_mul(PRIME);
}
}
}
pub(crate) fn lcg_next(state: &mut u64) -> u64 {
*state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
*state
}
pub(crate) fn lcg_f32(state: &mut u64) -> f32 {
lcg_next(state);
let u = (*state >> 16) as u32;
(u as f32 / u32::MAX as f32) * 2.0 - 1.0
}
pub(crate) fn all_finite(values: &[f32]) -> bool {
values.iter().all(|v| v.is_finite())
}