use bitrep::MomentsF64;
use std::collections::BTreeMap;
#[derive(Clone, PartialEq, Default)]
struct ReplicatedStats {
entries: BTreeMap<u32, MomentsF64>,
}
impl ReplicatedStats {
fn local_add(&mut self, replica: u32, x: f64) {
self.entries.entry(replica).or_default().add(x);
}
fn join(&mut self, other: &Self) {
for (r, m) in &other.entries {
match self.entries.get(r) {
Some(mine) if mine.count() >= m.count() => {}
_ => {
self.entries.insert(*r, m.clone());
}
}
}
}
fn global(&self) -> MomentsF64 {
let mut g = MomentsF64::new();
for m in self.entries.values() {
g.merge(m);
}
g
}
fn bytes(&self) -> Vec<u8> {
let mut out = Vec::new();
for (r, m) in &self.entries {
out.extend_from_slice(&r.to_le_bytes());
out.extend_from_slice(&m.to_bytes());
}
out
}
}
fn main() {
let mut a = ReplicatedStats::default();
let mut b = ReplicatedStats::default();
let mut c = ReplicatedStats::default();
let mut s = 0x9E3779B97F4A7C15u64;
let mut sample = || {
s ^= s << 13;
s ^= s >> 7;
s ^= s << 17;
1.0e8 + ((s >> 11) as f64 / (1u64 << 53) as f64 - 0.5) * 2e-3
};
for i in 0..30_000 {
let x = sample();
match i % 3 {
0 => a.local_add(0, x),
1 => b.local_add(1, x),
_ => c.local_add(2, x),
}
}
let mut order1 = a.clone();
order1.join(&b);
order1.join(&c);
let mut order2 = c.clone();
order2.join(&a);
order2.join(&b);
order2.join(&b); assert_eq!(
order1.bytes(),
order2.bytes(),
"join order / re-delivery changed state"
);
let mut idem = a.clone();
idem.join(&a.clone());
assert_eq!(idem.bytes(), a.bytes(), "idempotence");
let (mut ab, mut ba) = (a.clone(), b.clone());
ab.join(&b);
ba.join(&a);
assert_eq!(ab.bytes(), ba.bytes(), "commutativity");
let g = order1.global();
println!(
"replicated stats over {} samples, mean 1e8, spread 1e-3:",
g.count()
);
println!(" mean = {:.17e} (exactly rounded)", g.mean());
println!(" variance = {:.17e} (exactly rounded)", g.variance());
println!(" stddev = {:.17e}", g.stddev());
let n = g.count() as f64;
let naive_var = {
let mut s2 = 0.0f64;
let mut s1 = 0.0f64;
let mut st = 0x9E3779B97F4A7C15u64;
let mut sample = || {
st ^= st << 13;
st ^= st >> 7;
st ^= st << 17;
1.0e8 + ((st >> 11) as f64 / (1u64 << 53) as f64 - 0.5) * 2e-3
};
for _ in 0..30_000 {
let x = sample();
s1 += x;
s2 += x * x;
}
s2 / n - (s1 / n) * (s1 / n)
};
println!(" naive f64 textbook variance = {naive_var:.6e} <- catastrophic cancellation");
println!("\nCRDT laws verified: idempotent, commutative, join-order/duplicate safe.");
}