use super::projection::{Projection, ProjectionId};
const KURAMOTO_BYTES: usize = 3 * 4;
#[derive(Debug, Clone, Copy)]
pub struct KuramotoProjection {
pub theta: f32,
pub omega: f32,
pub coupling: f32,
}
impl Default for KuramotoProjection {
fn default() -> Self {
Self {
theta: 0.0,
omega: 0.0,
coupling: 1.0,
}
}
}
impl Projection for KuramotoProjection {
fn byte_size() -> usize {
KURAMOTO_BYTES
}
fn id() -> ProjectionId {
ProjectionId::Kuramoto
}
fn read(buf: &[u8]) -> Self {
assert!(buf.len() >= KURAMOTO_BYTES);
Self {
theta: f32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]),
omega: f32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]),
coupling: f32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
}
}
fn write(&self, buf: &mut [u8]) {
assert!(buf.len() >= KURAMOTO_BYTES);
buf[0..4].copy_from_slice(&self.theta.to_le_bytes());
buf[4..8].copy_from_slice(&self.omega.to_le_bytes());
buf[8..12].copy_from_slice(&self.coupling.to_le_bytes());
}
fn shape_hash_contribution(&self) -> u32 {
let mut hash = 0x811c_9dc5u32;
for byte in self.theta.to_bits().to_le_bytes() {
hash ^= byte as u32;
hash = hash.wrapping_mul(0x0100_0193);
}
hash
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::PI;
#[test]
fn test_kuramoto_byte_size() {
assert_eq!(KuramotoProjection::byte_size(), 12);
}
#[test]
fn test_kuramoto_roundtrip() {
let proj = KuramotoProjection {
theta: PI / 4.0,
omega: 1.5,
coupling: 2.0,
};
let mut buf = vec![0u8; KuramotoProjection::byte_size()];
proj.write(&mut buf);
let restored = KuramotoProjection::read(&buf);
assert!((restored.theta - PI / 4.0).abs() < 1e-6);
assert!((restored.omega - 1.5).abs() < 1e-6);
assert!((restored.coupling - 2.0).abs() < 1e-6);
}
}