Skip to main content

entrenar/quant/benchmarks/
generators.rs

1//! Weight generators for benchmarks
2//!
3//! Functions for generating synthetic weight distributions for testing.
4
5/// Generate Gaussian-like weight distribution (common in neural networks)
6pub fn generate_gaussian_weights(n: usize, mean: f32, std_dev: f32, seed: u64) -> Vec<f32> {
7    // Simple LCG for reproducibility
8    let mut state = seed;
9    let a: u64 = 1103515245;
10    let c: u64 = 12345;
11    let m: u64 = 1 << 31;
12
13    (0..n)
14        .map(|_| {
15            // Box-Muller transform (simplified)
16            state = (a.wrapping_mul(state).wrapping_add(c)) % m;
17            let u1 = (state as f32) / (m as f32);
18            state = (a.wrapping_mul(state).wrapping_add(c)) % m;
19            let u2 = (state as f32) / (m as f32);
20
21            let z = (-2.0 * u1.max(1e-10).ln()).sqrt() * (2.0 * std::f32::consts::PI * u2).cos();
22            mean + std_dev * z
23        })
24        .collect()
25}
26
27/// Generate uniform weights in range
28pub fn generate_uniform_weights(n: usize, min: f32, max: f32, seed: u64) -> Vec<f32> {
29    let mut state = seed;
30    let a: u64 = 1103515245;
31    let c: u64 = 12345;
32    let m: u64 = 1 << 31;
33
34    (0..n)
35        .map(|_| {
36            state = (a.wrapping_mul(state).wrapping_add(c)) % m;
37            let t = (state as f32) / (m as f32);
38            min + t * (max - min)
39        })
40        .collect()
41}
42
43/// Generate weights with outliers (to test robustness)
44pub fn generate_weights_with_outliers(
45    n: usize,
46    outlier_ratio: f32,
47    outlier_magnitude: f32,
48    seed: u64,
49) -> Vec<f32> {
50    let mut weights = generate_gaussian_weights(n, 0.0, 1.0, seed);
51    let num_outliers = (n as f32 * outlier_ratio) as usize;
52
53    let mut state = seed.wrapping_add(12345);
54    let a: u64 = 1103515245;
55    let c: u64 = 12345;
56    let m: u64 = 1 << 31;
57
58    for _ in 0..num_outliers {
59        state = (a.wrapping_mul(state).wrapping_add(c)) % m;
60        let idx = (state as usize) % n;
61        state = (a.wrapping_mul(state).wrapping_add(c)) % m;
62        let sign = if state.is_multiple_of(2) { 1.0 } else { -1.0 };
63        weights[idx] = sign * outlier_magnitude;
64    }
65
66    weights
67}
68
69/// Generate multi-channel weights (like conv/linear layer)
70pub fn generate_multi_channel_weights(
71    num_channels: usize,
72    features_per_channel: usize,
73    scale_variance: f32,
74    seed: u64,
75) -> Vec<f32> {
76    let mut weights = Vec::with_capacity(num_channels * features_per_channel);
77    let mut state = seed;
78    let a: u64 = 1103515245;
79    let c: u64 = 12345;
80    let m: u64 = 1 << 31;
81
82    for ch in 0..num_channels {
83        state = (a.wrapping_mul(state).wrapping_add(c)) % m;
84        let channel_scale = 1.0 + (ch as f32 / num_channels as f32) * scale_variance;
85
86        let channel_weights =
87            generate_gaussian_weights(features_per_channel, 0.0, channel_scale, state);
88        weights.extend(channel_weights);
89    }
90
91    weights
92}