compb-dla-model/src/system/nd.rs

108 lines
2.8 KiB
Rust

use std::ops::Add;
use num_integer::Integer;
use rand::Rng;
use serde::{Serialize, Serializer};
use serde::ser::SerializeMap;
use crate::system::GriddedPosition;
use crate::system::Storage;
pub struct NDVectorStorage<const DIM: usize> {
backing: Vec<bool>,
grid_size: u32,
}
impl<const DIM: usize> NDVectorStorage<DIM> {
pub fn new(grid_size: u32) -> Self {
Self { grid_size, backing: vec![false; grid_size.pow(DIM as u32) as usize] }
}
}
impl<const DIM: usize> Storage<NDPosition<DIM>> for NDVectorStorage<DIM> {
fn at(&self, position: &NDPosition<DIM>) -> bool {
return self.backing[position.linear_index(self.grid_size)];
}
fn deposit(&mut self, position: &NDPosition<DIM>) {
self.backing[position.linear_index(self.grid_size)] = true;
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NDPosition<const DIM: usize>([i32; DIM]);
impl<const DIM: usize> NDPosition<DIM> {
pub fn in_direction(direction: usize, value: i32) -> Self {
let mut arr = [0; DIM];
arr[direction] = value;
NDPosition(arr)
}
}
impl<const DIM: usize> Add for NDPosition<DIM> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.zip(rhs.0).map(|(a, b)| a + b))
}
}
impl<const DIM: usize> Serialize for NDPosition<DIM> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
let mut map = serializer.serialize_map(Some(DIM))?;
for (i, v) in self.0.iter().enumerate() {
map.serialize_entry(&format!("r{}", i), v)?;
}
map.end()
}
}
impl<const DIM: usize> GriddedPosition for NDPosition<DIM> {
const NEIGHBOURS: u32 = { 2u32.pow(DIM as u32) } as u32;
fn zero() -> Self {
NDPosition([0; DIM])
}
fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self {
let mut a: [f32; DIM] = [0f32; DIM];
let mut b: [i32; DIM] = [0i32; DIM];
for i in 0..DIM {
a[i] = rng.gen_range(0f32..1f32);
}
let norm = a.iter().sum::<f32>()
.sqrt();
for i in 0..DIM {
a[i] = a[i] * radius / norm;
b[i] = a[i] as i32;
}
return Self(b);
}
fn abs(&self) -> f32 {
let a: i32 = self.0.iter()
.map(|r| r.pow(2))
.sum();
(a as f32).powf(0.5)
}
fn neighbour(&self, neighbour_index: u32) -> Self {
let (dim, sign) = neighbour_index.div_rem(&(DIM as u32));
let sign = if sign == 0 { 1 } else { -1 };
let offset = Self::in_direction(dim as usize, sign);
self.clone() + offset
}
fn linear_index(&self, grid_size: u32) -> usize {
self.0.iter()
.enumerate()
.map(|(i, v)| (grid_size.pow(i as u32) as usize) * (v + ((grid_size / 2) as i32)) as usize)
.sum()
}
}