Compare commits
10 Commits
7e131af96d
...
92ef0f728c
| Author | SHA1 | Date | |
|---|---|---|---|
| 92ef0f728c | |||
| 973bcf0381 | |||
| f0e862616d | |||
| 1be8e3bd01 | |||
| 7cfa5092e8 | |||
| 1c49bf92c8 | |||
| 14b5cb4679 | |||
| f7ac576129 | |||
| cd1f20c1d2 | |||
| 0d972dc76a |
34
src/clib.rs
34
src/clib.rs
@ -1,5 +1,7 @@
|
|||||||
use crate::system::Position;
|
#![feature(array_zip)]
|
||||||
use crate::system::storage::{Storage, VectorStorage};
|
|
||||||
|
use system::Storage;
|
||||||
|
use crate::system::grid::{Position, VectorStorage};
|
||||||
|
|
||||||
mod system;
|
mod system;
|
||||||
|
|
||||||
@ -11,45 +13,29 @@ pub struct CStorage(VectorStorage);
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn storage_new(grid_size: u32) -> &'static mut CStorage {
|
pub extern "C" fn storage_new(grid_size: u32) -> &'static mut CStorage {
|
||||||
let mut pntr = Box::new(CStorage(VectorStorage::new(grid_size, 2)));
|
let mut pntr = Box::new(CStorage(VectorStorage::new(grid_size)));
|
||||||
Box::leak(pntr)
|
Box::leak(pntr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn storage_at(storage: &CStorage, i: i32, j: i32) -> bool {
|
pub extern "C" fn storage_at(storage: &CStorage, i: i32, j: i32) -> bool {
|
||||||
storage.0.at(&Position(i, j))
|
storage.0.at(&Position { x: i, y: j })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn storage_deposit(storage: &mut CStorage, i: i32, j: i32, val: u8) {
|
pub extern "C" fn storage_deposit(storage: &mut CStorage, i: i32, j: i32, val: u8) {
|
||||||
storage.0.write(&Position(i, j), val == 1);
|
storage.0.write(&Position { x: i, y: j }, val == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn walk(d: u32, i: i32, j: i32) -> CPosition {
|
pub extern "C" fn walk(d: u32, i: i32, j: i32) -> CPosition {
|
||||||
return test::b(d, i, j);
|
return test::b(d, i, j);
|
||||||
|
|
||||||
// match d {
|
|
||||||
// 0 => CPosition(i + 1, j),
|
|
||||||
// 1 => CPosition(i - 1, j),
|
|
||||||
// 2 => CPosition(i, j + 1),
|
|
||||||
// 3 => CPosition(i, j - 1),
|
|
||||||
// _ => panic!("Ahh"),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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 = Position::in_direction(1 - dim, sign * -1);
|
|
||||||
// let next = Position(i, j) + offset;
|
|
||||||
//
|
|
||||||
// CPosition(next.0, next.1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test {
|
mod test {
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use crate::CPosition;
|
use crate::CPosition;
|
||||||
use crate::system::Position;
|
use crate::system::grid::Position;
|
||||||
|
|
||||||
pub(crate) fn a(d: u32, i: i32, j: i32) -> CPosition {
|
pub(crate) fn a(d: u32, i: i32, j: i32) -> CPosition {
|
||||||
match d {
|
match d {
|
||||||
@ -66,9 +52,9 @@ mod test {
|
|||||||
let sign = if sign == 0 { 1 } else { -1 };
|
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.
|
// HACK: Our conventin and the MVA are different, since we are trying to strangle fig this, quick hack.
|
||||||
let offset = Position::in_direction(dim, sign);
|
let offset = Position::in_direction(dim, sign);
|
||||||
let next = Position(i, j) + offset;
|
let next = Position { x: i, y: j } + offset;
|
||||||
|
|
||||||
CPosition(next.0, next.1)
|
CPosition(next.x, next.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
36
src/example_systems.rs
Normal file
36
src/example_systems.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use rand::rngs::SmallRng;
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use crate::system::grid::{Position, VectorStorage};
|
||||||
|
use crate::system::model::DLASystem;
|
||||||
|
use crate::system::nd::{NDPosition, NDVectorStorage};
|
||||||
|
use crate::system::walker::LocalRandomWalker;
|
||||||
|
|
||||||
|
pub fn initial_config(seed: u64, max_particles: usize) -> DLASystem<SmallRng, Position, VectorStorage, LocalRandomWalker> {
|
||||||
|
DLASystem::new_g(
|
||||||
|
SmallRng::seed_from_u64(seed),
|
||||||
|
VectorStorage::new(1600),
|
||||||
|
LocalRandomWalker,
|
||||||
|
1.0,
|
||||||
|
max_particles,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stick_probability(seed: u64, max_particles: usize, stick_probability: f32) -> DLASystem<SmallRng, Position, VectorStorage, LocalRandomWalker> {
|
||||||
|
DLASystem::new_g(
|
||||||
|
SmallRng::seed_from_u64(seed),
|
||||||
|
VectorStorage::new(1600),
|
||||||
|
LocalRandomWalker,
|
||||||
|
stick_probability,
|
||||||
|
max_particles,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn three_dimensional(seed: u64, max_particles: usize, stick_probability: f32) -> DLASystem<SmallRng, NDPosition<3>, NDVectorStorage<3>, LocalRandomWalker> {
|
||||||
|
DLASystem::new_g(
|
||||||
|
SmallRng::seed_from_u64(seed),
|
||||||
|
NDVectorStorage::new(1600),
|
||||||
|
LocalRandomWalker,
|
||||||
|
stick_probability,
|
||||||
|
max_particles,
|
||||||
|
)
|
||||||
|
}
|
||||||
15
src/main.rs
15
src/main.rs
@ -1,16 +1,21 @@
|
|||||||
|
#![feature(array_zip)]
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
mod system;
|
mod system;
|
||||||
|
mod example_systems;
|
||||||
|
|
||||||
use system::walker::{Walker, LocalRandomWalker};
|
use system::walker::{LocalRandomWalker, Walker};
|
||||||
use system::storage::{Storage, VectorStorage};
|
use system::grid::VectorStorage;
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use rand::rngs::SmallRng;
|
use rand::rngs::SmallRng;
|
||||||
use crate::system::{DIM, Position};
|
use crate::system::grid::Position;
|
||||||
use crate::system::model::DLASystem;
|
use crate::system::model::DLASystem;
|
||||||
|
use crate::system::Storage;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use crate::example_systems::stick_probability;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
@ -25,8 +30,8 @@ fn main() {
|
|||||||
|
|
||||||
println!("Running: {:?}", cli);
|
println!("Running: {:?}", cli);
|
||||||
|
|
||||||
let mut sys = DLASystem::<SmallRng, VectorStorage, LocalRandomWalker>::new(
|
let mut sys = stick_probability(
|
||||||
SmallRng::seed_from_u64(cli.seed),
|
cli.seed,
|
||||||
cli.max_particles,
|
cli.max_particles,
|
||||||
cli.stick_probability
|
cli.stick_probability
|
||||||
);
|
);
|
||||||
|
|||||||
104
src/system/grid.rs
Normal file
104
src/system/grid.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use std::f32::consts::PI;
|
||||||
|
use std::ops::Add;
|
||||||
|
use num_integer::Integer;
|
||||||
|
use rand::Rng;
|
||||||
|
use crate::system::{GriddedPosition, Storage};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
pub struct VectorStorage {
|
||||||
|
backing: Vec<bool>,
|
||||||
|
grid_size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Position {
|
||||||
|
pub x: i32,
|
||||||
|
pub y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
pub fn in_direction(direction: u32, value: i32) -> Self {
|
||||||
|
if direction == 0 { Position { x: value, y: 0 } } else { Position { x: 0, y: value } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Position {
|
||||||
|
type Output = Position;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Position { x: self.x + rhs.x, y: self.y + rhs.y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GriddedPosition for Position {
|
||||||
|
const NEIGHBOURS: u32 = 4;
|
||||||
|
|
||||||
|
fn zero() -> Position {
|
||||||
|
Position { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self {
|
||||||
|
let theta = rng.gen_range(0f32..1.0) * 2.0 * PI;
|
||||||
|
let (x, y) = (radius * theta.cos(), radius * theta.sin());
|
||||||
|
Position { x: x as i32, y: y as i32 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abs(&self) -> f32 {
|
||||||
|
((self.x.pow(2) + self.y.pow(2)) as f32).powf(0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neighbour(&self, neighbour_index: u32) -> Self {
|
||||||
|
let (dim, sign) = neighbour_index.div_rem(&2);
|
||||||
|
let sign = if sign == 0 { 1 } else { -1 };
|
||||||
|
let offset = Position::in_direction(dim, sign);
|
||||||
|
|
||||||
|
self.clone() + offset
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linear_index(&self, grid_size: u32) -> usize {
|
||||||
|
let grid_size = grid_size as i32;
|
||||||
|
|
||||||
|
assert!(self.x <= grid_size && -(grid_size) <= self.x);
|
||||||
|
assert!(self.y <= grid_size && -(grid_size) <= self.y);
|
||||||
|
|
||||||
|
let x = (self.x + (grid_size) / 2) as usize;
|
||||||
|
let y = (self.y + (grid_size) / 2) as usize;
|
||||||
|
|
||||||
|
return grid_size as usize * y + x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VectorStorage {
|
||||||
|
pub fn new(grid_size: u32) -> VectorStorage {
|
||||||
|
VectorStorage { grid_size, backing: vec![false; grid_size.pow(2) as usize] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_index(&self, position: &Position) -> usize {
|
||||||
|
assert!(position.x <= self.grid_size as i32 && -(self.grid_size as i32) <= position.x);
|
||||||
|
assert!(position.y <= self.grid_size as i32 && -(self.grid_size as i32) <= position.y);
|
||||||
|
|
||||||
|
let x = (position.x + (self.grid_size as i32) / 2) as usize;
|
||||||
|
let y = (position.y + (self.grid_size as i32) / 2) as usize;
|
||||||
|
|
||||||
|
return self.grid_size as usize * y + x
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience function for c-binding
|
||||||
|
* */
|
||||||
|
pub fn write(&mut self, position: &Position, val: bool) {
|
||||||
|
let index = self.linear_index(position);
|
||||||
|
self.backing[index] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage<Position> for VectorStorage {
|
||||||
|
fn at(&self, position: &Position) -> bool {
|
||||||
|
return self.backing[self.linear_index(position)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deposit(&mut self, position: &Position) {
|
||||||
|
let index = self.linear_index(position);
|
||||||
|
self.backing[index] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,45 +1,26 @@
|
|||||||
|
use std::f32::consts::PI;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use serde::{Serialize, Deserialize};
|
use num_integer::Integer;
|
||||||
|
use rand::Rng;
|
||||||
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
|
use crate::system::grid::VectorStorage;
|
||||||
|
|
||||||
pub mod walker;
|
pub mod walker;
|
||||||
pub mod storage;
|
pub mod grid;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
pub mod nd;
|
||||||
|
|
||||||
pub(crate) const DIM: u32 = 2;
|
pub trait GriddedPosition: Add<Output=Self> + Serialize + Clone {
|
||||||
|
const NEIGHBOURS: u32;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
fn zero() -> Self;
|
||||||
pub struct Position {
|
fn spawn<R: Rng>(rng: &mut R, radius: f32) -> Self;
|
||||||
x: i32,
|
fn abs(&self) -> f32;
|
||||||
y: i32,
|
fn neighbour(&self, neighbour_index: u32) -> Self;
|
||||||
|
fn linear_index(&self, grid_size: u32) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
pub trait Storage<P: GriddedPosition> {
|
||||||
pub fn zero() -> Position {
|
fn at(&self, position: &P) -> bool;
|
||||||
Position { x: 0, y: 0 }
|
fn deposit(&mut self, position: &P);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn abs(&self) -> f32 {
|
|
||||||
((self.x.pow(2) + self.y.pow(2)) as f32).powf(0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn in_direction(direction: u32, value: i32) -> Self {
|
|
||||||
if direction == 0 { Position { x: value, y: 0 } } else { Position { x: 0, y: value } }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn neighbours(&self) -> impl Iterator<Item=Self> + '_ {
|
|
||||||
let a = (0..DIM).into_iter();
|
|
||||||
|
|
||||||
return a.flat_map(|direction| [
|
|
||||||
self.clone() + Position::in_direction(direction, 1),
|
|
||||||
self.clone() + Position::in_direction(direction, -1),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Position {
|
|
||||||
type Output = Position;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
Position { x: self.x + rhs.x, y: self.y + rhs.y }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,14 +4,15 @@ use std::io::Write;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::system::{DIM, Position};
|
use crate::system::{GriddedPosition, grid::Position, Storage};
|
||||||
use crate::system::storage::{Storage, VectorStorage};
|
use crate::system::grid::VectorStorage;
|
||||||
use crate::system::walker::{LocalRandomWalker, Walker};
|
use crate::system::walker::{LocalRandomWalker, Walker};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::system::nd::{NDPosition, NDVectorStorage};
|
||||||
|
|
||||||
pub struct DLASystem<R: Rng, S: Storage, W: Walker<R>> {
|
pub struct DLASystem<R: Rng, P: GriddedPosition, S: Storage<P>, W: Walker<P>> {
|
||||||
rng: R,
|
rng: R,
|
||||||
storage: S,
|
space: S,
|
||||||
walker: W,
|
walker: W,
|
||||||
|
|
||||||
stick_probability: f32,
|
stick_probability: f32,
|
||||||
@ -19,8 +20,8 @@ pub struct DLASystem<R: Rng, S: Storage, W: Walker<R>> {
|
|||||||
|
|
||||||
pub running: bool,
|
pub running: bool,
|
||||||
|
|
||||||
particles: Vec<Position>,
|
particles: Vec<P>,
|
||||||
active_particle: Option<Position>,
|
active_particle: Option<P>,
|
||||||
|
|
||||||
add_ratio: f32,
|
add_ratio: f32,
|
||||||
add_circle: f32,
|
add_circle: f32,
|
||||||
@ -29,16 +30,16 @@ pub struct DLASystem<R: Rng, S: Storage, W: Walker<R>> {
|
|||||||
cluster_radius: f32,
|
cluster_radius: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Rng, S: Storage, W: Walker<R>> DLASystem<R, S, W> {
|
impl<R: Rng, P: GriddedPosition, S: Storage<P>, W: Walker<P>> DLASystem<R, P, S, W> {
|
||||||
pub fn new(rng: R, max_particles: usize, stick_probability: f32) -> DLASystem<R, VectorStorage, LocalRandomWalker> {
|
pub fn new_g(rng: R, space: S, walker: W, stick_probability: f32, max_particles: usize) -> Self {
|
||||||
let mut sys: DLASystem<R, VectorStorage, LocalRandomWalker> = DLASystem {
|
let mut sys = DLASystem {
|
||||||
rng,
|
rng,
|
||||||
stick_probability,
|
stick_probability,
|
||||||
max_particles,
|
max_particles,
|
||||||
running: true,
|
running: true,
|
||||||
|
|
||||||
storage: VectorStorage::new(1600, 2),
|
space,
|
||||||
walker: LocalRandomWalker::new(DIM),
|
walker,
|
||||||
particles: vec![],
|
particles: vec![],
|
||||||
active_particle: None,
|
active_particle: None,
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ impl<R: Rng, S: Storage, W: Walker<R>> DLASystem<R, S, W> {
|
|||||||
cluster_radius: 0.0,
|
cluster_radius: 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
sys.deposit(&Position::zero());
|
sys.deposit(&P::zero());
|
||||||
|
|
||||||
sys
|
sys
|
||||||
}
|
}
|
||||||
@ -76,7 +77,7 @@ impl<R: Rng, S: Storage, W: Walker<R>> DLASystem<R, S, W> {
|
|||||||
|
|
||||||
if distance > self.kill_circle {
|
if distance > self.kill_circle {
|
||||||
self.active_particle = None;
|
self.active_particle = None;
|
||||||
} else if !self.storage.at(&next_position) {
|
} else if !self.space.at(&next_position) {
|
||||||
if self.check_stick(&next_position) {
|
if self.check_stick(&next_position) {
|
||||||
self.deposit(&next_position);
|
self.deposit(&next_position);
|
||||||
self.active_particle = None;
|
self.active_particle = None;
|
||||||
@ -87,27 +88,26 @@ impl<R: Rng, S: Storage, W: Walker<R>> DLASystem<R, S, W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_stick(&mut self, position: &Position) -> bool {
|
fn check_stick(&mut self, position: &P) -> bool {
|
||||||
position.neighbours()
|
(0..P::NEIGHBOURS)
|
||||||
|
.map(|n| position.neighbour(n))
|
||||||
.any(|neighbour|
|
.any(|neighbour|
|
||||||
self.storage.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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_particle(&mut self) {
|
fn spawn_particle(&mut self) {
|
||||||
let theta = self.rng.gen_range(0f32..1.0) * 2.0 * PI;
|
let position = P::spawn(&mut self.rng, self.add_circle);
|
||||||
let (x, y) = (self.add_circle * theta.cos(), self.add_circle * theta.sin());
|
|
||||||
let position = Position { x: x as i32, y: y as i32 };
|
|
||||||
|
|
||||||
if !self.storage.at(&position) {
|
if !self.space.at(&position) {
|
||||||
self.active_particle = Some(position);
|
self.active_particle = Some(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deposit(&mut self, p0: &Position) {
|
fn deposit(&mut self, p0: &P) {
|
||||||
self.particles.push(p0.clone());
|
self.particles.push(p0.clone());
|
||||||
self.storage.deposit(p0);
|
self.space.deposit(p0);
|
||||||
|
|
||||||
let distance = p0.abs();
|
let distance = p0.abs();
|
||||||
if distance > self.cluster_radius {
|
if distance > self.cluster_radius {
|
||||||
|
|||||||
107
src/system/nd.rs
Normal file
107
src/system/nd.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
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] / 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,47 +0,0 @@
|
|||||||
use crate::system::Position;
|
|
||||||
|
|
||||||
pub trait Storage {
|
|
||||||
fn at(&self, position: &Position) -> bool;
|
|
||||||
fn deposit(&mut self, position: &Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VectorStorage {
|
|
||||||
backing: Vec<bool>,
|
|
||||||
grid_size: u32,
|
|
||||||
dim: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VectorStorage {
|
|
||||||
pub fn new(grid_size: u32, dim: u32) -> VectorStorage {
|
|
||||||
VectorStorage { grid_size, dim, backing: vec![false; grid_size.pow(dim) as usize] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn linear_index(&self, position: &Position) -> usize {
|
|
||||||
assert!(position.x <= self.grid_size as i32 && -(self.grid_size as i32) <= position.x);
|
|
||||||
assert!(position.y <= self.grid_size as i32 && -(self.grid_size as i32) <= position.y);
|
|
||||||
|
|
||||||
let x = (position.x + (self.grid_size as i32) / 2) as usize;
|
|
||||||
let y = (position.y + (self.grid_size as i32) / 2) as usize;
|
|
||||||
|
|
||||||
return self.grid_size as usize * y + x
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convenience function for c-binding
|
|
||||||
* */
|
|
||||||
pub fn write(&mut self, position: &Position, val: bool) {
|
|
||||||
let index = self.linear_index(position);
|
|
||||||
self.backing[index] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Storage for VectorStorage {
|
|
||||||
fn at(&self, position: &Position) -> bool {
|
|
||||||
return self.backing[self.linear_index(position)]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deposit(&mut self, position: &Position) {
|
|
||||||
let index = self.linear_index(position);
|
|
||||||
self.backing[index] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,42 +1,32 @@
|
|||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use rand::prelude::Rng;
|
use rand::prelude::Rng;
|
||||||
use crate::system::{DIM, Position};
|
use crate::system::{GriddedPosition, grid::Position};
|
||||||
|
|
||||||
pub trait Walker<R: Rng> {
|
pub trait Walker<P: GriddedPosition> {
|
||||||
fn walk(&self, rng: &mut R, position: &Position) -> Position;
|
fn walk<R: Rng>(&self, rng: &mut R, position: &P) -> P;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LocalRandomWalker {
|
pub struct LocalRandomWalker;
|
||||||
dim: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LocalRandomWalker {
|
impl<Position: GriddedPosition> Walker<Position> for LocalRandomWalker {
|
||||||
pub(crate) fn new(dim: u32) -> LocalRandomWalker { LocalRandomWalker { dim } }
|
fn walk<R: Rng>(&self, rng: &mut R, position: &Position) -> Position {
|
||||||
}
|
position.neighbour(rng.gen_range(0u32..Position::NEIGHBOURS))
|
||||||
|
|
||||||
impl<R: Rng> Walker<R> for LocalRandomWalker {
|
|
||||||
fn walk(&self, rng: &mut R, position: &Position) -> Position {
|
|
||||||
let (dim, sign) = rng.gen_range(0u32..(DIM * 2)).div_rem(&self.dim);
|
|
||||||
let sign = if sign == 0 { 1 } else { -1 };
|
|
||||||
let offset = Position::in_direction(dim, sign);
|
|
||||||
|
|
||||||
position.clone() + offset
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test {
|
mod test {
|
||||||
use rand::rngs::SmallRng;
|
use rand::rngs::SmallRng;
|
||||||
use rand::{SeedableRng, thread_rng};
|
use rand::{SeedableRng, thread_rng};
|
||||||
use crate::system::Position;
|
use crate::system::{GriddedPosition, grid::Position};
|
||||||
use crate::system::walker::{LocalRandomWalker, Walker};
|
use crate::system::walker::{LocalRandomWalker, Walker};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn uniformity() {
|
fn uniformity() {
|
||||||
let walker = LocalRandomWalker::new(2);
|
let walker = LocalRandomWalker::new();
|
||||||
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
|
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
|
||||||
let mut results: Vec<Position> = vec![];
|
let mut results: Vec<Position> = vec![];
|
||||||
|
|
||||||
let origin = &Position(0, 0);
|
let origin = &Position::zero();
|
||||||
|
|
||||||
let x: u32 = (1_000000_000);
|
let x: u32 = (1_000000_000);
|
||||||
for i in 0..x {
|
for i in 0..x {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user