Skip to main content

math_audio_optimisation/
init_sobol.rs

1/// Generate Sobol quasi-random sequence for initialization.
2///
3/// Uses Van der Corput sequences in co-prime bases for better parameter space
4/// coverage than pure random initialization.
5///
6/// # Arguments
7/// * `dimensions` - Number of dimensions (parameters)
8/// * `num_samples` - Number of samples to generate
9/// * `bounds` - Parameter bounds for scaling
10///
11/// # Returns
12/// Vector of parameter vectors sampled from the quasi-random sequence
13pub fn init_sobol(dimensions: usize, num_samples: usize, bounds: &[(f64, f64)]) -> Vec<Vec<f64>> {
14    let mut samples = Vec::with_capacity(num_samples);
15
16    for i in 0..num_samples {
17        let mut sample = Vec::with_capacity(dimensions);
18
19        for (dim, &(lower, upper)) in bounds.iter().enumerate().take(dimensions) {
20            let base = match dim {
21                0 => 2,
22                1 => 3,
23                2 => 5,
24                3 => 7,
25                4 => 11,
26                _ => 2 + (dim % 10),
27            };
28
29            let quasi_random = van_der_corput(i + 1, base);
30            sample.push(lower + quasi_random * (upper - lower));
31        }
32
33        samples.push(sample);
34    }
35
36    samples
37}
38
39/// Van der Corput sequence for quasi-random number generation.
40fn van_der_corput(mut n: usize, base: usize) -> f64 {
41    let mut result = 0.0;
42    let mut f = 1.0 / base as f64;
43
44    while n > 0 {
45        result += (n % base) as f64 * f;
46        n /= base;
47        f /= base as f64;
48    }
49
50    result
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_van_der_corput() {
59        let val1 = van_der_corput(1, 2);
60        let val2 = van_der_corput(2, 2);
61        let val3 = van_der_corput(3, 2);
62
63        assert!((0.0..1.0).contains(&val1));
64        assert!((0.0..1.0).contains(&val2));
65        assert!((0.0..1.0).contains(&val3));
66
67        assert_ne!(val1, val2);
68        assert_ne!(val2, val3);
69    }
70
71    #[test]
72    fn test_init_sobol() {
73        let bounds = vec![(0.0, 10.0), (0.1, 5.0), (-12.0, 12.0)];
74        let samples = init_sobol(3, 5, &bounds);
75
76        assert_eq!(samples.len(), 5);
77        for sample in &samples {
78            assert_eq!(sample.len(), 3);
79            assert!((0.0..=10.0).contains(&sample[0]));
80            assert!((0.1..=5.0).contains(&sample[1]));
81            assert!((-12.0..=12.0).contains(&sample[2]));
82        }
83    }
84}