terminals_core/substrate/
kuramoto.rs1use super::projection::{Projection, ProjectionId};
8
9const KURAMOTO_BYTES: usize = 3 * 4;
11
12#[derive(Debug, Clone, Copy)]
13pub struct KuramotoProjection {
14 pub theta: f32,
16 pub omega: f32,
18 pub coupling: f32,
20}
21
22impl Default for KuramotoProjection {
23 fn default() -> Self {
24 Self {
25 theta: 0.0,
26 omega: 0.0,
27 coupling: 1.0,
28 }
29 }
30}
31
32impl Projection for KuramotoProjection {
33 fn byte_size() -> usize {
34 KURAMOTO_BYTES
35 }
36
37 fn id() -> ProjectionId {
38 ProjectionId::Kuramoto
39 }
40
41 fn read(buf: &[u8]) -> Self {
42 assert!(buf.len() >= KURAMOTO_BYTES);
43 Self {
44 theta: f32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]),
45 omega: f32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]),
46 coupling: f32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
47 }
48 }
49
50 fn write(&self, buf: &mut [u8]) {
51 assert!(buf.len() >= KURAMOTO_BYTES);
52 buf[0..4].copy_from_slice(&self.theta.to_le_bytes());
53 buf[4..8].copy_from_slice(&self.omega.to_le_bytes());
54 buf[8..12].copy_from_slice(&self.coupling.to_le_bytes());
55 }
56
57 fn shape_hash_contribution(&self) -> u32 {
58 let mut hash = 0x811c_9dc5u32;
59 for byte in self.theta.to_bits().to_le_bytes() {
60 hash ^= byte as u32;
61 hash = hash.wrapping_mul(0x0100_0193);
62 }
63 hash
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use std::f32::consts::PI;
71
72 #[test]
73 fn test_kuramoto_byte_size() {
74 assert_eq!(KuramotoProjection::byte_size(), 12);
75 }
76
77 #[test]
78 fn test_kuramoto_roundtrip() {
79 let proj = KuramotoProjection {
80 theta: PI / 4.0,
81 omega: 1.5,
82 coupling: 2.0,
83 };
84 let mut buf = vec![0u8; KuramotoProjection::byte_size()];
85 proj.write(&mut buf);
86 let restored = KuramotoProjection::read(&buf);
87 assert!((restored.theta - PI / 4.0).abs() < 1e-6);
88 assert!((restored.omega - 1.5).abs() < 1e-6);
89 assert!((restored.coupling - 2.0).abs() < 1e-6);
90 }
91}