Skip to main content

spin_sim/statistics/
stats.rs

1/// Running statistics accumulator for per-temperature observables.
2pub struct Statistics {
3    pub count: usize,
4    pub aggregate: Vec<f64>,
5    pub power: u32,
6}
7
8impl Statistics {
9    pub fn new(n_temps: usize, power: u32) -> Self {
10        Self {
11            count: 0,
12            aggregate: vec![0.0; n_temps],
13            power,
14        }
15    }
16
17    pub fn update(&mut self, values: &[f32]) {
18        self.count += 1;
19        for (agg, &v) in self.aggregate.iter_mut().zip(values.iter()) {
20            let v = v as f64;
21            *agg += if self.power == 1 {
22                v
23            } else {
24                v.powi(self.power as i32)
25            };
26        }
27    }
28
29    /// Mean per temperature; NaN when nothing was recorded.
30    pub fn average(&self) -> Vec<f64> {
31        let c = self.count as f64;
32        self.aggregate.iter().map(|&a| a / c).collect()
33    }
34
35    /// Per-temperature `⟨v²⟩ - ⟨v⟩²` from first- and second-power accumulators of the
36    /// same samples; NaN when nothing was recorded.
37    pub fn variance(first: &Self, second: &Self) -> Vec<f64> {
38        debug_assert!(first.power == 1 && second.power == 2 && first.count == second.count);
39        first
40            .average()
41            .iter()
42            .zip(second.average())
43            .map(|(mean, mean_square)| mean_square - mean * mean)
44            .collect()
45    }
46}