use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct TrustVector(pub u8);
impl TrustVector {
pub const COUNT: usize = 48;
pub fn all_directions() -> [(i16, i16, i16, i16); 48] {
[
(1, 1, 0, 1), (-1, 1, 0, 1), (0, 1, 1, 1), (0, 1, -1, 1),
(3, 5, 4, 5), (-3, 5, 4, 5), (3, 5, -4, 5), (-3, 5, -4, 5),
(4, 5, 3, 5), (-4, 5, 3, 5), (4, 5, -3, 5), (-4, 5, -3, 5),
(5, 13, 12, 13), (-5, 13, 12, 13), (5, 13, -12, 13), (-5, 13, -12, 13),
(12, 13, 5, 13), (-12, 13, 5, 13), (12, 13, -5, 13), (-12, 13, -5, 13),
(7, 25, 24, 25), (-7, 25, 24, 25), (7, 25, -24, 25), (-7, 25, -24, 25),
(24, 25, 7, 25), (-24, 25, 7, 25), (24, 25, -7, 25), (-24, 25, -7, 25),
(8, 17, 15, 17), (-8, 17, 15, 17), (8, 17, -15, 17), (-8, 17, -15, 17),
(15, 17, 8, 17), (-15, 17, 8, 17), (15, 17, -8, 17), (-15, 17, -8, 17),
(9, 41, 40, 41), (-9, 41, 40, 41), (9, 41, -40, 41), (-9, 41, -40, 41),
(40, 41, 9, 41), (-40, 41, 9, 41), (40, 41, -9, 41), (-40, 41, -9, 41),
(15, 17, -8, 17), (-15, 17, -8, 17), (15, 17, 8, 17), (-15, 17, 8, 17),
]
}
pub fn to_f32(&self) -> (f32, f32) {
let (xn, xd, yn, yd) = Self::all_directions()[self.0 as usize];
(xn as f32 / xd as f32, yn as f32 / yd as f32)
}
pub fn from_f32(x: f32, y: f32) -> Self {
let mut best = 0;
let mut best_dist = f32::MAX;
for (i, (xn, xd, yn, yd)) in Self::all_directions().iter().enumerate() {
let dx = x - (*xn as f32 / *xd as f32);
let dy = y - (*yn as f32 / *yd as f32);
let dist = dx * dx + dy * dy;
if dist < best_dist {
best_dist = dist;
best = i;
}
}
TrustVector(best as u8)
}
pub fn bits(&self) -> f64 {
5.58496
}
}
#[derive(Clone)]
pub struct TrustTopology {
}
impl TrustTopology {
pub fn new() -> Self {
Self {}
}
pub fn encode(&self, x: f32, y: f32) -> TrustVector {
TrustVector::from_f32(x, y)
}
pub fn decode(&self, v: TrustVector) -> (f32, f32) {
v.to_f32()
}
pub fn encode_batch(&self, vectors: &[[f32; 2]]) -> Vec<TrustVector> {
vectors.iter().map(|v| self.encode(v[0], v[1])).collect()
}
pub const BITS_PER_VECTOR: f64 = 5.58496;
pub const MAX_NEIGHBORS: usize = 12;
}
impl Default for TrustTopology {
fn default() -> Self {
Self::new()
}
}
pub fn build_trust_topology(
_agents: &[u64],
neighbor_pairs: &[(usize, usize)],
positions: &[[f32; 2]],
) -> Vec<TrustVector> {
let mut trust_vectors = Vec::new();
for &(i, j) in neighbor_pairs {
let (x, y) = (positions[j][0] - positions[i][0], positions[j][1] - positions[i][1]);
let mag = (x * x + y * y).sqrt();
let (nx, ny) = if mag > 1e-6 { (x / mag, y / mag) } else { (0.0, 1.0) };
trust_vectors.push(TrustVector::from_f32(nx, ny));
}
trust_vectors
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_no_drift() {
let original = (0.6_f32, 0.8_f32);
let encoded = TrustVector::from_f32(original.0, original.1);
let (dx, dy) = encoded.to_f32();
assert!((dx - original.0).abs() < 0.01);
assert!((dy - original.1).abs() < 0.01);
}
#[test]
fn test_all_48_directions_on_circle() {
for i in 0..48 {
let v = TrustVector(i as u8);
let (x, y) = v.to_f32();
let mag = (x * x + y * y).sqrt();
assert!((mag - 1.0).abs() < 0.001, "direction {i} not on unit circle");
}
}
#[test]
fn test_bits_per_vector() {
assert!((TrustTopology::BITS_PER_VECTOR - 5.58496).abs() < 0.0001);
}
#[test]
fn test_trust_topology_encode_decode() {
let topology = TrustTopology::new();
let v = topology.encode(0.6, 0.8);
let (x, y) = topology.decode(v);
assert!((x - 0.6).abs() < 0.01);
assert!((y - 0.8).abs() < 0.01);
}
}