From 10c7450c8a3dce579baddce2d1a41a5e0066e37c Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Fri, 10 Mar 2023 15:28:42 +0000 Subject: [PATCH] Add DiagonalWalkera and fix 3D KD grid --- Cargo.lock | 1 + Cargo.toml | 1 + src/cli/cli.rs | 1 + src/cli/output.rs | 2 +- src/clib.rs | 77 ------------------------------------ src/main.rs | 31 ++++++++++----- src/system/spaces/kd_grid.rs | 36 ++++++++++++----- src/system/sticker.rs | 13 +++++- src/system/walker.rs | 28 ++++++++++++- 9 files changed, 90 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e73413..6211eeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2837,6 +2837,7 @@ dependencies = [ name = "rust-codebase" version = "0.1.0" dependencies = [ + "anyhow", "bevy", "cbindgen", "clap 4.1.8", diff --git a/Cargo.toml b/Cargo.toml index 9aed74f..01c4e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ serde_json = "1.0.93" kd-tree = { version = "0.5.1", features = ["nalgebra"] } nalgebra = "0.32.2" kiddo = "0.2.5" +anyhow = "1.0.69" [build-dependencies] cbindgen = "0.24.3" diff --git a/src/cli/cli.rs b/src/cli/cli.rs index a2246b4..c9105ce 100644 --- a/src/cli/cli.rs +++ b/src/cli/cli.rs @@ -38,6 +38,7 @@ pub enum PCM { Initial(InitialCli), StickProbability(StickProbabilityCli), Grid3KD(StickProbabilityCli), + Grid3KDTsang(StickProbabilityCli), Grid3(StickProbabilityCli), Hex(StickProbabilityCli), Balls(BallsCli), diff --git a/src/cli/output.rs b/src/cli/output.rs index eb9abbb..732f65c 100644 --- a/src/cli/output.rs +++ b/src/cli/output.rs @@ -39,6 +39,6 @@ fn write_csv_positions, W: Walker

, Sp: Spa fn write_json_full_data, W: Walker

, Sp: Spawner

, St: Sticker>(sys: &DLASystem, output_path: &Path) { let file = File::create(output_path).expect("Failed to open file"); - serde_json::to_writer(file, &sys.history) + serde_json::to_writer_pretty(file, &sys.history) .expect("Failed to write json"); } diff --git a/src/clib.rs b/src/clib.rs index 1790dbf..32fc4d2 100644 --- a/src/clib.rs +++ b/src/clib.rs @@ -2,80 +2,3 @@ pub extern "C" fn dla_rust_disabled() -> bool { true } - -// #![feature(array_zip)] -// -// use system::Storage; -// use crate::system::spaces::square_grid::Grid2D; -// use crate::system::spaces::VectorStorage; -// -// mod system; -// -// #[derive(Eq, PartialEq, Debug)] -// #[repr(C)] -// pub struct CPosition(i32, i32); -// -// pub struct CStorage(VectorStorage); -// -// #[no_mangle] -// pub extern "C" fn storage_new(grid_size: u32) -> &'static mut CStorage { -// let mut pntr = Box::new(CStorage(VectorStorage::new(grid_size))); -// Box::leak(pntr) -// } -// -// #[no_mangle] -// pub extern "C" fn storage_at(storage: &CStorage, i: i32, j: i32) -> bool { -// storage.0.at(&Grid2D { x: i, y: j }) -// } -// -// #[no_mangle] -// pub extern "C" fn storage_deposit(storage: &mut CStorage, i: i32, j: i32, val: u8) { -// storage.0.inner.(&Grid2D { x: i, y: j }, val == 1); -// } -// -// #[no_mangle] -// pub extern "C" fn walk(d: u32, i: i32, j: i32) -> CPosition { -// return test::b(d, i, j); -// } -// -// // mod test { -// // use num_integer::Integer; -// // use crate::CPosition; -// // use crate::system::grid::Grid2D; -// // -// // pub(crate) fn a(d: u32, i: i32, j: i32) -> CPosition { -// // match d { -// // 0 => CPosition(i + 1, j), -// // 1 => CPosition(i - 1, j), -// // 2 => CPosition(i, j + 1), -// // 3 => CPosition(i, j - 1), -// // _ => panic!("Ahh"), -// // } -// // } -// // -// // pub(crate) fn b(d: u32, i: i32, j: i32) -> CPosition { -// // let (dim, sign) = d.div_rem(&2); -// // let sign = if sign == 0 { 1 } else { -1 }; -// // // HACK: Our conventin and the MVA are different, since we are trying to strangle fig this, quick hack. -// // let offset = Grid2D::in_direction(dim, sign); -// // let next = Grid2D { x: i, y: j } + offset; -// // -// // CPosition(next.x, next.y) -// // } -// // -// // #[test] -// // fn test() { -// // let d = [0, 1, 2, 3]; -// // d.iter() -// // .map(|d| d.div_rem(&2)) -// // .for_each(|p| println!("{p:?}")); -// // } -// // -// // #[test] -// // fn alignment() { -// // let d = [0, 1, 2, 3]; -// // d.iter() -// // .map(|d| (a(*d, 0, 0), b(*d, 0, 0))) -// // .for_each(|p| assert_eq!(p.0, p.1)); -// // } -// // } diff --git a/src/main.rs b/src/main.rs index ba94bc3..5aa7cec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ #![feature(generic_const_exprs)] #![feature(let_chains)] -use std::ops::Deref; use clap::Parser; use rand::prelude::*; use crate::cli::{drive_system}; @@ -12,12 +11,12 @@ use crate::surface_probability_measure::{LoggerSticker, ReadOnlyVectorStorage}; use crate::system::model::DLASystem; use crate::system::spaces::continuous::{ContinuousSticker, ContinuousStorage, ContinuousWalker}; use crate::system::spaces::hexagonal::HexPosition; -use crate::system::spaces::kd_grid::{KDGrid, KDGrid2Sticker}; +use crate::system::spaces::kd_grid::{KDSpace}; use crate::system::spaces::square_grid::{Grid2D, Grid3D}; use crate::system::spaces::VectorStorage; use crate::system::spawner::UniformSpawner; use crate::system::sticker::{ProbabilisticSticking, SimpleSticking}; -use crate::system::walker::LocalRandomWalker; +use crate::system::walker::{DiagonalRandomWalker, LocalRandomWalker}; mod system; mod surface_probability_measure; @@ -49,7 +48,7 @@ fn main() { VectorStorage::new(grid_size, 2), LocalRandomWalker, UniformSpawner, - ProbabilisticSticking { stick_probability }, + ProbabilisticSticking::new(stick_probability).unwrap(), cli.max_particles, ); @@ -58,12 +57,26 @@ fn main() { } PCM::Grid3KD(StickProbabilityCli { grid_size, stick_probability }) => { - let mut sys = DLASystem::<_, Grid2D, _, _, _, _>::new( + let mut sys = DLASystem::<_, Grid3D, _, _, _, _>::new( SmallRng::seed_from_u64(cli.seed), - KDGrid { inner: kiddo::KdTree::new() }, + KDSpace::new(), LocalRandomWalker, UniformSpawner, - KDGrid2Sticker { stick_probability }, + ProbabilisticSticking::new(stick_probability).unwrap(), + cli.max_particles, + ); + + drive_system(&mut sys, cli.max_frames, cli.notify_every); + write(&sys, cli.format, &cli.output); + } + + PCM::Grid3KDTsang(StickProbabilityCli { grid_size, stick_probability }) => { + let mut sys = DLASystem::<_, Grid3D, _, _, _, _>::new( + SmallRng::seed_from_u64(cli.seed), + KDSpace::new(), + DiagonalRandomWalker, + UniformSpawner, + ProbabilisticSticking::new(stick_probability).unwrap(), cli.max_particles, ); @@ -77,7 +90,7 @@ fn main() { VectorStorage::new(grid_size, 3), LocalRandomWalker, UniformSpawner, - ProbabilisticSticking { stick_probability }, + ProbabilisticSticking::new(stick_probability).unwrap(), cli.max_particles, ); @@ -91,7 +104,7 @@ fn main() { VectorStorage::new(grid_size, 2), LocalRandomWalker, UniformSpawner, - ProbabilisticSticking { stick_probability }, + ProbabilisticSticking::new(stick_probability).unwrap(), cli.max_particles, ); diff --git a/src/system/spaces/kd_grid.rs b/src/system/spaces/kd_grid.rs index 3d3634a..94e3220 100644 --- a/src/system/spaces/kd_grid.rs +++ b/src/system/spaces/kd_grid.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use rand::Rng; use crate::system::{GriddedPosition, Position, Storage}; use crate::system::spaces::square_grid::{Grid2D, Grid3D}; @@ -11,11 +12,17 @@ fn taxicab_grid3(a: &[f32; 3], b: &[f32; 3]) -> f32 { (a[0] - b[0]).abs() + (a[1] - b[1]).abs() + (a[2] - b[2]).abs() } -pub struct KDGrid { +pub struct KDSpace { pub(crate) inner: kiddo::KdTree, } -impl Storage for KDGrid<2> { +impl KDSpace { + pub fn new() -> KDSpace { + KDSpace { inner: kiddo::KdTree::new() } + } +} + +impl Storage for KDSpace<2> { fn is_occupied(&self, position: &Grid2D) -> bool { let a = self.inner.best_n_within(&[position.x as f32, position.y as f32], 0f32, 1, &taxicab_grid2).unwrap(); !a.is_empty() @@ -27,7 +34,7 @@ impl Storage for KDGrid<2> { } } -impl Storage for KDGrid<3> { +impl Storage for KDSpace<3> { fn is_occupied(&self, position: &Grid3D) -> bool { let a = self.inner.best_n_within(&[position.x as f32, position.y as f32, position.z as f32], 0f32, 1, &taxicab_grid3).unwrap(); !a.is_empty() @@ -39,13 +46,22 @@ impl Storage for KDGrid<3> { } } - -pub struct KDGrid2Sticker { +pub struct KDProbabilisticSticking { pub(crate) stick_probability: f32, } -impl Sticker> for KDGrid2Sticker { - fn should_stick(&self, rng: &mut R, space: &KDGrid<2>, position: &Grid2D) -> bool { +impl KDProbabilisticSticking { + fn new(stick_probability: f32) -> anyhow::Result { + return if 0f32 < stick_probability && stick_probability <= 1f32 { + Ok(KDProbabilisticSticking { stick_probability }) + } else { + Err(anyhow!("Sticking probability outside of (0, 1] range.")) + } + } +} + +impl Sticker> for KDProbabilisticSticking { + fn should_stick(&self, rng: &mut R, space: &KDSpace<2>, position: &Grid2D) -> bool { let a = space.inner.best_n_within(&[position.x as f32, position.y as f32], 1f32, Grid2D::NEIGHBOURS as usize, &taxicab_grid2) .unwrap(); @@ -53,14 +69,14 @@ impl Sticker> for KDGrid2Sticker { return false; } - let q = (1f32 - self.stick_probability); + let q = 1f32 - self.stick_probability; let a = q.powi(a.len() as i32); rng.gen_range(0f32..1f32) > a } } -impl Sticker> for KDGrid2Sticker { - fn should_stick(&self, rng: &mut R, space: &KDGrid<3>, position: &Grid3D) -> bool { +impl Sticker> for KDProbabilisticSticking { + fn should_stick(&self, rng: &mut R, space: &KDSpace<3>, position: &Grid3D) -> bool { let a = space.inner.best_n_within(&[position.x as f32, position.y as f32, position.z as f32], 1f32, Grid2D::NEIGHBOURS as usize, &taxicab_grid3) .unwrap(); diff --git a/src/system/sticker.rs b/src/system/sticker.rs index e096100..def10a7 100644 --- a/src/system/sticker.rs +++ b/src/system/sticker.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use rand::Rng; use crate::system::{GriddedPosition, Position, Storage}; @@ -8,7 +9,17 @@ pub trait Sticker> { pub struct SimpleSticking; pub struct ProbabilisticSticking { - pub stick_probability: f32 + pub(crate) stick_probability: f32 +} + +impl ProbabilisticSticking { + pub fn new(stick_probability: f32) -> anyhow::Result { + return if 0f32 < stick_probability && stick_probability <= 1f32 { + Ok(ProbabilisticSticking { stick_probability }) + } else { + Err(anyhow!("Sticking probability outside of (0, 1] range.")) + } + } } impl> Sticker for SimpleSticking { diff --git a/src/system/walker.rs b/src/system/walker.rs index 8d848c7..7becd27 100644 --- a/src/system/walker.rs +++ b/src/system/walker.rs @@ -1,5 +1,6 @@ use rand::prelude::Rng; use crate::system::{GriddedPosition, Position}; +use crate::system::spaces::square_grid::Grid3D; pub trait Walker { fn walk(&self, rng: &mut R, position: &P) -> P; @@ -13,12 +14,25 @@ impl Walker

for LocalRandomWalker { } } +pub struct DiagonalRandomWalker; + +impl Walker for DiagonalRandomWalker { + fn walk(&self, rng: &mut R, position: &Grid3D) -> Grid3D { + let a: Vec = (0..3) + .map(|r| rng.gen_range(-1..=1)) + .collect(); + + position.clone() + Grid3D::from_cartesian([a[0] as f32, a[1] as f32, a[2] as f32]) + } +} + mod test { use rand::rngs::SmallRng; use rand::{SeedableRng, thread_rng}; + use crate::cli::cli::PCM::Grid3; use crate::system::{GriddedPosition, Position}; - use crate::system::spaces::square_grid::Grid2D; - use crate::system::walker::{LocalRandomWalker, Walker}; + use crate::system::spaces::square_grid::{Grid2D, Grid3D}; + use crate::system::walker::{DiagonalRandomWalker, LocalRandomWalker, Walker}; #[test] fn uniformity() { @@ -55,4 +69,14 @@ mod test { println!("{} {} {} {}", a as f32 / x as f32, b as f32 / x as f32, c as f32 / x as f32, d as f32 / x as f32); } + + #[test] + fn diagonal() { + let drw = DiagonalRandomWalker; + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + + for _ in 0..20 { + println!("{:?}", drw.walk(&mut rng, &Grid3D::zero())) + } + } }