use ans::{decode, encode, FrequencyTable};
use fingerprints::{entropy_plugin_bits, entropy_plugin_nats_from_counts, Fingerprint};
fn main() {
println!("=== ANS Coding Efficiency vs Theoretical Entropy ===\n");
let distributions: Vec<(&str, Vec<u32>)> = vec![
("Uniform(8)", vec![100; 8]),
("Zipf-like", vec![1000, 500, 250, 125, 63, 31, 16, 8, 4, 2]),
("Highly skewed", vec![10000, 100, 10, 1, 1, 1, 1, 1]),
("Binary (90/10)", vec![900, 100]),
("Near-deterministic", vec![9999, 1]),
];
println!(
" {:20} | {:>8} | {:>8} | {:>10} | {:>10} | {:>6}",
"Distribution", "H (bits)", "Symbols", "Theor (B)", "ANS (B)", "Redund"
);
println!(
" {:-<20}-+-{:-<8}-+-{:-<8}-+-{:-<10}-+-{:-<10}-+-{:-<6}",
"", "", "", "", "", ""
);
for (name, counts) in &distributions {
let mut symbols = Vec::new();
for (sym, &count) in counts.iter().enumerate() {
for _ in 0..count {
symbols.push(sym as u32);
}
}
let n_symbols = symbols.len();
let usize_counts: Vec<usize> = counts.iter().map(|&c| c as usize).collect();
let h_nats = entropy_plugin_nats_from_counts(&usize_counts).unwrap_or(0.0);
let h_bits = h_nats / std::f64::consts::LN_2;
let theoretical_bytes = (h_bits * n_symbols as f64 / 8.0).ceil() as usize;
let fp = Fingerprint::from_counts(usize_counts.iter().copied()).unwrap();
let h_fp = entropy_plugin_bits(&fp);
let table = FrequencyTable::from_counts(counts, 14).unwrap();
let encoded = encode(&symbols, &table).unwrap();
let ans_bytes = encoded.len();
let decoded = decode(&encoded, &table, n_symbols).unwrap();
assert_eq!(decoded, symbols, "roundtrip failed for {name}");
let ans_bits_per_sym = (ans_bytes * 8) as f64 / n_symbols as f64;
let redundancy = ans_bits_per_sym - h_bits;
println!(
" {:20} | {:8.4} | {:8} | {:10} | {:10} | {:+.4}",
name, h_bits, n_symbols, theoretical_bytes, ans_bytes, redundancy
);
assert!(
(h_bits - h_fp).abs() < 1e-6,
"entropy mismatch: from_counts={h_bits} vs Fingerprint={h_fp}"
);
}
println!("\n Redundancy = (ANS bits/sym) - H(X). Closer to 0 = better.");
println!(" Negative values possible due to rounding (integer bytes).");
}