use crate::codebook::Codebook;
use crate::hyper::Hyper;
#[derive(Clone)]
pub struct HoloSet {
codebook: Codebook,
memory: Hyper,
len: usize,
}
impl HoloSet {
pub fn new(dim: usize, universe: usize, seed: u64) -> Self {
let codebook = Codebook::new(dim, universe, seed);
let memory = Hyper::zeros(dim);
HoloSet {
codebook,
memory,
len: 0,
}
}
#[inline]
pub fn dim(&self) -> usize {
self.codebook.dim()
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn memory(&self) -> &Hyper {
&self.memory
}
pub fn insert(&mut self, id: usize) {
self.memory.bundle_into(&self.codebook.atom(id));
self.len += 1;
}
pub fn similarity(&self, id: usize) -> f32 {
self.memory.dot(&self.codebook.atom(id)) / self.dim() as f32
}
pub fn contains(&self, id: usize) -> bool {
self.similarity(id) > 0.5
}
pub fn batch_contains(&self, ids: &[usize]) -> Vec<bool> {
let scores = self
.codebook
.scores_batch(core::slice::from_ref(&self.memory));
let row = &scores[0];
let threshold = 0.5 * self.dim() as f32;
ids.iter().map(|&id| row[id] > threshold).collect()
}
pub fn estimated_cardinality(&self) -> f64 {
let n = self.memory.dot(&self.memory) as f64;
n / self.dim() as f64
}
pub fn union(&self, other: &HoloSet) -> HoloSet {
assert_eq!(self.dim(), other.dim(), "sets must share a dimension");
assert_eq!(
self.codebook.seed(),
other.codebook.seed(),
"sets must share a codebook"
);
let mut memory = self.memory.clone();
memory.bundle_into(&other.memory);
HoloSet {
codebook: self.codebook.clone(),
memory,
len: self.len + other.len,
}
}
}
impl core::fmt::Debug for HoloSet {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"HoloSet {{ dim: {}, inserts: {}, ~card: {:.1} }}",
self.dim(),
self.len,
self.estimated_cardinality()
)
}
}