use holographic_memory::core::entangled::EntangledHVec;
const DIM: usize = 16384;
const DENOM: usize = 256;
const MAX_ITEMS: usize = 5000;
const N_PROBES: usize = 200;
fn load_points() -> Vec<usize> {
vec![10, 50, 100, 200, 500, 700, 1000, 2000, 5000]
}
fn mean(vals: &[f64]) -> f64 {
if vals.is_empty() {
return 0.0;
}
vals.iter().sum::<f64>() / vals.len() as f64
}
fn fmin(vals: &[f64]) -> f64 {
vals.iter().cloned().fold(f64::INFINITY, f64::min)
}
fn fmax(vals: &[f64]) -> f64 {
vals.iter().cloned().fold(f64::NEG_INFINITY, f64::max)
}
fn generate_items() -> (Vec<EntangledHVec>, Vec<EntangledHVec>) {
let items: Vec<EntangledHVec> = (0..MAX_ITEMS)
.map(|i| EntangledHVec::new_with_density(DIM, DENOM, i as u64 * 37 + 1))
.collect();
let non_members: Vec<EntangledHVec> = (0..N_PROBES)
.map(|i| EntangledHVec::new_with_density(DIM, DENOM, (MAX_ITEMS + i) as u64 * 37 + 9999))
.collect();
(items, non_members)
}
fn print_header() {
println!(
"scheme\tn_items\tmember_mean\tmember_min\tnonmember_mean\tnonmember_max\tgap\tfirst100_recall"
);
}
fn measure_stats(
members: &[EntangledHVec],
non_members: &[EntangledHVec],
bundle: &EntangledHVec,
) -> (f64, f64, f64, f64, f64) {
let member_sims: Vec<f64> = members
.iter()
.map(|item| item.corrected_containment(bundle))
.collect();
let member_mean = mean(&member_sims);
let member_min = fmin(&member_sims);
let nonmember_sims: Vec<f64> = non_members
.iter()
.map(|item| item.corrected_containment(bundle))
.collect();
let nonmember_mean = mean(&nonmember_sims);
let nonmember_max = fmax(&nonmember_sims);
let gap = member_min - nonmember_max;
(member_mean, member_min, nonmember_mean, nonmember_max, gap)
}
fn recall_first100(items: &[EntangledHVec], bundle: &EntangledHVec) -> f64 {
let count = items.len().min(100);
if count == 0 {
return 1.0;
}
let recalled = items[..count]
.iter()
.filter(|item| item.corrected_containment(bundle) > 0.5)
.count();
recalled as f64 / count as f64
}
fn run_sliding_window(items: &[EntangledHVec], non_members: &[EntangledHVec], window_size: usize) {
let scheme = format!("sliding_w{}", window_size);
for &n in &load_points() {
if n > MAX_ITEMS {
break;
}
let window_start = n.saturating_sub(window_size);
let window = &items[window_start..n];
let bundle = EntangledHVec::bundle_bloom(window);
let (mm, mmin, nmm, nmmax, gap) = measure_stats(window, non_members, &bundle);
let r100 = recall_first100(items, &bundle);
println!(
"{}\t{}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.4}",
scheme, n, mm, mmin, nmm, nmmax, gap, r100
);
}
}
fn run_majority_vote(items: &[EntangledHVec], non_members: &[EntangledHVec]) {
for &n in &load_points() {
if n > MAX_ITEMS {
break;
}
let bundle = EntangledHVec::bundle(&items[..n]);
let member_sims: Vec<f64> = items[..n]
.iter()
.map(|item| item.similarity(&bundle))
.collect();
let nonmember_sims: Vec<f64> = non_members
.iter()
.map(|item| item.similarity(&bundle))
.collect();
let mm = mean(&member_sims);
let mmin = fmin(&member_sims);
let nmm = mean(&nonmember_sims);
let nmmax = fmax(&nonmember_sims);
let gap = mmin - nmmax;
let r100_count = items[..100.min(n)]
.iter()
.filter(|item| item.similarity(&bundle) > nmmax)
.count();
let r100 = r100_count as f64 / 100.0_f64.min(n as f64);
println!(
"majority\t{}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.4}",
n, mm, mmin, nmm, nmmax, gap, r100
);
}
}
fn run_reservoir(items: &[EntangledHVec], non_members: &[EntangledHVec], reservoir_size: usize) {
use holographic_memory::core::entangled::hash_u64;
let scheme = format!("reservoir_r{}", reservoir_size);
for &n in &load_points() {
if n > MAX_ITEMS {
break;
}
let mut reservoir: Vec<usize> = Vec::with_capacity(reservoir_size);
for i in 0..n {
if i < reservoir_size {
reservoir.push(i);
} else {
let r = (hash_u64(42, i as u64) % (i as u64 + 1)) as usize;
if r < reservoir_size {
reservoir[r] = i;
}
}
}
let reservoir_items: Vec<&EntangledHVec> =
reservoir.iter().map(|&idx| &items[idx]).collect();
let bundle = EntangledHVec::bundle_bloom(&reservoir_items);
let member_sims: Vec<f64> = reservoir
.iter()
.map(|&idx| items[idx].corrected_containment(&bundle))
.collect();
let mm = mean(&member_sims);
let mmin = fmin(&member_sims);
let nonmember_sims: Vec<f64> = non_members
.iter()
.map(|item| item.corrected_containment(&bundle))
.collect();
let nmm = mean(&nonmember_sims);
let nmmax = fmax(&nonmember_sims);
let gap = mmin - nmmax;
let first100_in_reservoir = reservoir.iter().filter(|&&idx| idx < 100).count();
let r100 = first100_in_reservoir as f64 / 100.0_f64.min(n as f64);
println!(
"{}\t{}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.4}",
scheme, n, mm, mmin, nmm, nmmax, gap, r100
);
}
}
fn run_tiered_window(items: &[EntangledHVec], non_members: &[EntangledHVec], w1: usize, w2: usize) {
let scheme = format!("tiered_{}_{}", w1, w2);
for &n in &load_points() {
if n > MAX_ITEMS {
break;
}
let t1_start = n.saturating_sub(w1);
let tier1_items = &items[t1_start..n];
let bundle_t1 = EntangledHVec::bundle_bloom(tier1_items);
let t2_end = t1_start;
let t2_start = t2_end.saturating_sub(w2);
let has_tier2 = t2_end > t2_start;
let bundle_t2 = if has_tier2 {
Some(EntangledHVec::bundle_bloom(&items[t2_start..t2_end]))
} else {
None
};
let combined_score = |item: &EntangledHVec| -> f64 {
let s1 = item.corrected_containment(&bundle_t1);
let s2 = bundle_t2
.as_ref()
.map(|b| item.corrected_containment(b) * 0.5)
.unwrap_or(0.0);
s1.max(s2)
};
let all_tier_start = t2_start.min(t1_start);
let member_sims: Vec<f64> = items[all_tier_start..n]
.iter()
.map(&combined_score)
.collect();
let mm = mean(&member_sims);
let mmin = fmin(&member_sims);
let nonmember_sims: Vec<f64> = non_members.iter().map(&combined_score).collect();
let nmm = mean(&nonmember_sims);
let nmmax = fmax(&nonmember_sims);
let gap = mmin - nmmax;
let r100_count = items[..100.min(n)]
.iter()
.filter(|item| combined_score(item) > 0.5)
.count();
let r100 = r100_count as f64 / 100.0_f64.min(n as f64);
println!(
"{}\t{}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.4}",
scheme, n, mm, mmin, nmm, nmmax, gap, r100
);
}
}
fn run_flat_bloom(items: &[EntangledHVec], non_members: &[EntangledHVec]) {
for &n in &load_points() {
if n > MAX_ITEMS {
break;
}
let bundle = EntangledHVec::bundle_bloom(&items[..n]);
let density = bundle.indices().len() as f64 / DIM as f64;
let (mm, mmin, nmm, nmmax, gap) = measure_stats(&items[..n], non_members, &bundle);
let r100 = recall_first100(items, &bundle);
println!(
"flat_bloom\t{}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.6}\t{:.4}",
n, mm, mmin, nmm, nmmax, gap, r100
);
if density > 0.995 {
break;
}
}
}
fn main() {
println!(
"# Window experiments: D={} denom={} max_items={} probes={}",
DIM, DENOM, MAX_ITEMS, N_PROBES
);
println!("# gap = member_min - nonmember_max (>0 means perfect separation)");
println!("# first100_recall = fraction of first 100 items retrievable at each load point");
println!();
let (items, non_members) = generate_items();
print_header();
run_flat_bloom(&items, &non_members);
println!();
print_header();
run_sliding_window(&items, &non_members, 100);
println!();
print_header();
run_sliding_window(&items, &non_members, 200);
println!();
print_header();
run_sliding_window(&items, &non_members, 500);
println!();
print_header();
run_majority_vote(&items, &non_members);
println!();
print_header();
run_reservoir(&items, &non_members, 100);
println!();
print_header();
run_reservoir(&items, &non_members, 200);
println!();
print_header();
run_reservoir(&items, &non_members, 500);
println!();
print_header();
run_tiered_window(&items, &non_members, 100, 400);
println!();
println!("# SUMMARY");
println!("# flat_bloom: unbounded growth, gap hits 0 around n=700");
println!("# sliding_wN: bounded at N items, gap stays positive, old items forgotten (FIFO)");
println!("# majority: threshold vote, sparse output, limited capacity");
println!("# reservoir_rN: bounded at N items, gap stays positive, uniform forgetting");
println!("# tiered: two-tier temporal priority, wider effective window");
}