Files
wifi-densepose/vendor/ruvector/examples/ultra-low-latency-sim/src/hierarchical.rs

222 lines
6.4 KiB
Rust

//! Hierarchical Meta-Simulation
//!
//! Each level of hierarchy compresses BATCH_SIZE simulations into one result.
//! Level k represents BATCH_SIZE^k simulations per output value.
/// Default batch size for hierarchical compression
pub const DEFAULT_BATCH_SIZE: usize = 64;
/// Hierarchical simulation compressor
/// Each output represents BATCH_SIZE^level input simulations
#[repr(align(64))]
pub struct HierarchicalCompressor {
/// Current results (each represents many sub-simulations)
results: Vec<f32>,
/// Hierarchy level
level: u32,
/// Batch size for compression
batch_size: usize,
}
impl HierarchicalCompressor {
/// Create new compressor at given hierarchy level
pub fn new(output_size: usize, level: u32, batch_size: usize) -> Self {
Self {
results: vec![0.0; output_size],
level,
batch_size,
}
}
/// Simulations represented by each result value
pub fn sims_per_result(&self) -> u64 {
(self.batch_size as u64).pow(self.level)
}
/// Total simulations represented by all results
pub fn total_simulations(&self) -> u64 {
self.results.len() as u64 * self.sims_per_result()
}
/// Compress batch of inputs into meta-results
/// Aggregates BATCH_SIZE values per output
#[inline]
pub fn compress(&mut self, inputs: &[f32]) {
let out_count = inputs.len() / self.batch_size;
for (i, result) in self.results.iter_mut().take(out_count).enumerate() {
let start = i * self.batch_size;
let end = start + self.batch_size;
// Sum and average (vectorizable loop)
let sum: f32 = inputs[start..end].iter().sum();
*result = sum / self.batch_size as f32;
}
}
/// Get compressed results
pub fn results(&self) -> &[f32] {
&self.results
}
/// Hierarchy level
pub fn level(&self) -> u32 {
self.level
}
}
/// Multi-level hierarchical simulation pipeline
/// Compresses through multiple levels for exponential multiplier
pub struct HierarchicalPipeline {
/// Compressors for each level
levels: Vec<HierarchicalCompressor>,
/// Batch size
batch_size: usize,
}
impl HierarchicalPipeline {
/// Create pipeline with given depth
pub fn new(base_size: usize, depth: usize, batch_size: usize) -> Self {
let mut levels = Vec::with_capacity(depth);
let mut size = base_size;
for level in 0..depth as u32 {
size /= batch_size;
if size == 0 { size = 1; }
levels.push(HierarchicalCompressor::new(size, level + 1, batch_size));
}
Self { levels, batch_size }
}
/// Run full compression pipeline
pub fn compress_all(&mut self, base_inputs: &[f32]) {
if self.levels.is_empty() { return; }
// First level compresses base inputs
self.levels[0].compress(base_inputs);
// Each subsequent level compresses previous level's output
for i in 1..self.levels.len() {
let prev_results = self.levels[i - 1].results.clone();
self.levels[i].compress(&prev_results);
}
}
/// Total simulations at final level
pub fn final_simulations(&self) -> u64 {
self.levels.last()
.map(|l| l.total_simulations())
.unwrap_or(0)
}
/// Get final results
pub fn final_results(&self) -> Option<&[f32]> {
self.levels.last().map(|l| l.results())
}
}
/// Ensemble aggregator for Monte Carlo with hierarchical batching
/// Each "sample" represents many underlying random samples
pub struct EnsembleAggregator {
/// Running mean estimates
means: Vec<f64>,
/// Running M2 for Welford's online variance
m2: Vec<f64>,
/// Sample count (each "sample" = batch_size underlying samples)
count: u64,
/// Samples per aggregate
samples_per_aggregate: u64,
}
impl EnsembleAggregator {
/// Create aggregator for n-dimensional output
pub fn new(dimensions: usize, samples_per_aggregate: u64) -> Self {
Self {
means: vec![0.0; dimensions],
m2: vec![0.0; dimensions],
count: 0,
samples_per_aggregate,
}
}
/// Add aggregate sample (represents many underlying samples)
/// Using Welford's online algorithm for numerical stability
#[inline]
pub fn add_aggregate(&mut self, values: &[f64]) {
self.count += 1;
let n = self.count as f64;
for (i, &x) in values.iter().enumerate() {
let delta = x - self.means[i];
self.means[i] += delta / n;
let delta2 = x - self.means[i];
self.m2[i] += delta * delta2;
}
}
/// Total underlying samples represented
pub fn total_samples(&self) -> u64 {
self.count * self.samples_per_aggregate
}
/// Get current mean estimates
pub fn means(&self) -> &[f64] {
&self.means
}
/// Get sample variance
pub fn variance(&self) -> Vec<f64> {
if self.count < 2 {
return vec![0.0; self.means.len()];
}
self.m2.iter().map(|m| m / (self.count - 1) as f64).collect()
}
/// Standard error (adjusted for aggregation)
pub fn standard_error(&self) -> Vec<f64> {
let var = self.variance();
let n = self.total_samples() as f64;
var.iter().map(|v| (v / n).sqrt()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hierarchical_compressor() {
let mut comp = HierarchicalCompressor::new(16, 1, 64);
let inputs: Vec<f32> = (0..1024).map(|i| i as f32).collect();
comp.compress(&inputs);
assert_eq!(comp.results().len(), 16);
assert_eq!(comp.sims_per_result(), 64);
assert_eq!(comp.total_simulations(), 16 * 64);
}
#[test]
fn test_hierarchical_pipeline() {
let mut pipeline = HierarchicalPipeline::new(4096, 3, 4);
let inputs: Vec<f32> = (0..4096).map(|i| (i as f32).sin()).collect();
pipeline.compress_all(&inputs);
assert!(pipeline.final_simulations() > 0);
}
#[test]
fn test_ensemble_aggregator() {
let mut agg = EnsembleAggregator::new(2, 1000);
for i in 0..100 {
agg.add_aggregate(&[i as f64, -i as f64]);
}
assert_eq!(agg.total_samples(), 100_000);
assert!((agg.means()[0] - 49.5).abs() < 0.1);
}
}