use std::path::PathBuf;
use std::time::Instant;
use horon::{DurabilityMode, Horon, HoronConfig};
use g_math::fixed_point::FixedPoint;
const SEM_DIMS: u8 = 20;
fn coords(user_vals: &[f64]) -> Vec<u8> {
let mut out = vec![0u8; SEM_DIMS as usize * 16];
for (d, v) in user_vals.iter().enumerate() {
let off = (16 + d) * 16;
out[off..off + 16].copy_from_slice(&FixedPoint::from_f64(*v).raw().to_le_bytes());
}
out
}
fn ma_config(partial: bool) -> HoronConfig {
HoronConfig {
dimension: 4,
semantic_dims: SEM_DIMS,
compression: false,
auto_compact_threshold: 0,
partial_reads: partial,
meaning_addressed: true,
semantic_bounds: (0.0, 1000.0),
durability: DurabilityMode::Relaxed,
..Default::default()
}
}
fn rnd(i: usize, salt: usize) -> f64 {
let x = (i.wrapping_mul(2654435761) ^ salt.wrapping_mul(40503)) as u32;
(x as f64) / (u32::MAX as f64)
}
fn main() {
for &n in &[10_000usize, 50_000, 100_000] {
let path = PathBuf::from(format!("/tmp/scan_counts_{}.htt", n));
let _ = std::fs::remove_file(&path);
let build_start = Instant::now();
{
let gf = Horon::open_with_config(&path, ma_config(false)).unwrap();
for i in 0..n {
let cluster = i % 100;
let cx = 10.0 + (cluster % 10) as f64 * 100.0;
let cy = 10.0 + (cluster / 10) as f64 * 100.0;
let c = [
cx + rnd(i, 1) * 10.0 - 5.0,
cy + rnd(i, 2) * 10.0 - 5.0,
rnd(i, 3) * 1000.0,
rnd(i, 4) * 1000.0,
];
let key = format!("/e/c{:03}/{:06}", cluster, i);
gf.put_data_only(&key, b"x").unwrap();
gf.set_semantic(&key, coords(&c)).unwrap();
}
gf.compact().unwrap(); }
let build_secs = build_start.elapsed().as_secs_f64();
let gf = Horon::open_with_config(&path, ma_config(true)).unwrap();
let mut touched_total = 0usize;
let mut window_time = 0.0f64;
let queries = 20;
for q in 0..queries {
let cluster = (q * 7) % 100;
let qc = [
10.0 + (cluster % 10) as f64 * 100.0 + 2.0,
10.0 + (cluster / 10) as f64 * 100.0 - 2.0,
500.0,
500.0,
];
let t = Instant::now();
let hits = gf.nearest_semantic(&coords(&qc), 10, 16..18).unwrap();
window_time += t.elapsed().as_secs_f64();
assert_eq!(hits.len(), 10);
touched_total += gf.last_semantic_scan_count().unwrap_or(0);
}
let avg_touched = touched_total / queries;
println!(
"n={:>6} build+compact {:>6.1}s windowed: avg {:>6} entries touched ({:>5.2}% of file), {:>8.3} ms/query (brute-force baseline: {} entries = 100%)",
n,
build_secs,
avg_touched,
100.0 * avg_touched as f64 / n as f64,
1000.0 * window_time / queries as f64,
n,
);
let _ = std::fs::remove_file(&path);
}
}