Halve run-time by swapping to index based neighbours to avoid need for allocating Vecs

This commit is contained in:
Joshua Coles 2023-03-04 14:18:16 +00:00
parent f0e862616d
commit 973bcf0381
4 changed files with 22 additions and 18 deletions

View File

@ -1,5 +1,6 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use std::ops::Add; use std::ops::Add;
use num_integer::Integer;
use rand::Rng; use rand::Rng;
use serde::{Serialize, Deserialize, Serializer}; use serde::{Serialize, Deserialize, Serializer};
@ -9,10 +10,12 @@ pub mod model;
pub mod nd; pub mod nd;
pub trait GriddedPosition: Add<Output=Self> + Serialize + Clone { pub trait GriddedPosition: Add<Output=Self> + Serialize + Clone {
const NEIGHBOURS: u32;
fn zero() -> Self; fn zero() -> Self;
fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self; fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self;
fn abs(&self) -> f32; fn abs(&self) -> f32;
fn neighbours(&self) -> Vec<Self>; fn neighbour(&self, neighbour_index: u32) -> Self;
fn linear_index(&self, grid_size: u32) -> usize; fn linear_index(&self, grid_size: u32) -> usize;
} }
@ -37,6 +40,8 @@ impl Add for Position {
} }
impl GriddedPosition for Position { impl GriddedPosition for Position {
const NEIGHBOURS: u32 = 4;
fn zero() -> Position { fn zero() -> Position {
Position { x: 0, y: 0 } Position { x: 0, y: 0 }
} }
@ -51,13 +56,12 @@ impl GriddedPosition for Position {
((self.x.pow(2) + self.y.pow(2)) as f32).powf(0.5) ((self.x.pow(2) + self.y.pow(2)) as f32).powf(0.5)
} }
fn neighbours(&self) -> Vec<Self> { fn neighbour(&self, neighbour_index: u32) -> Self {
let a = (0..2).into_iter(); let (dim, sign) = neighbour_index.div_rem(&2);
let sign = if sign == 0 { 1 } else { -1 };
let offset = Position::in_direction(dim, sign);
return a.flat_map(|direction| [ self.clone() + offset
self.clone() + Position::in_direction(direction, 1),
self.clone() + Position::in_direction(direction, -1),
]).collect();
} }
fn linear_index(&self, grid_size: u32) -> usize { fn linear_index(&self, grid_size: u32) -> usize {

View File

@ -114,8 +114,8 @@ impl<R: Rng, P: GriddedPosition, S: Storage<P>, W: Walker<P>> DLASystem<R, P, S,
} }
fn check_stick(&mut self, position: &P) -> bool { fn check_stick(&mut self, position: &P) -> bool {
position.neighbours() (0..P::NEIGHBOURS)
.iter() .map(|n| position.neighbour(n))
.any(|neighbour| .any(|neighbour|
self.space.at(&neighbour) self.space.at(&neighbour)
&& self.rng.gen_range(0.0f32..=1.0) < self.stick_probability && self.rng.gen_range(0.0f32..=1.0) < self.stick_probability

View File

@ -1,4 +1,5 @@
use std::ops::Add; use std::ops::Add;
use num_integer::Integer;
use rand::Rng; use rand::Rng;
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use serde::ser::SerializeMap; use serde::ser::SerializeMap;
@ -56,6 +57,8 @@ impl<const DIM: usize> Serialize for NDPosition<DIM> {
} }
impl<const DIM: usize> GriddedPosition for NDPosition<DIM> { impl<const DIM: usize> GriddedPosition for NDPosition<DIM> {
const NEIGHBOURS: u32 = { 2u32.pow(DIM as u32) } as u32;
fn zero() -> Self { fn zero() -> Self {
NDPosition([0; DIM]) NDPosition([0; DIM])
} }
@ -87,13 +90,12 @@ impl<const DIM: usize> GriddedPosition for NDPosition<DIM> {
(a as f32).powf(0.5) (a as f32).powf(0.5)
} }
fn neighbours(&self) -> Vec<Self> { fn neighbour(&self, neighbour_index: u32) -> Self {
let a = (0..DIM).into_iter(); 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);
return a.flat_map(|direction| [ self.clone() + offset
self.clone() + NDPosition::in_direction(direction, 1),
self.clone() + NDPosition::in_direction(direction, -1),
]).collect();
} }
fn linear_index(&self, grid_size: u32) -> usize { fn linear_index(&self, grid_size: u32) -> usize {

View File

@ -10,9 +10,7 @@ pub struct LocalRandomWalker;
impl<Position: GriddedPosition> Walker<Position> for LocalRandomWalker { impl<Position: GriddedPosition> Walker<Position> for LocalRandomWalker {
fn walk<R: Rng>(&self, rng: &mut R, position: &Position) -> Position { fn walk<R: Rng>(&self, rng: &mut R, position: &Position) -> Position {
let neighbours = position.neighbours(); position.neighbour(rng.gen_range(0u32..Position::NEIGHBOURS))
let index = rng.gen_range(0..(neighbours.len()));
neighbours[index].clone()
} }
} }