From 6a2d19e98417c9c5cdea7c88969b111fdbb081c8 Mon Sep 17 00:00:00 2001 From: mindv0rtex Date: Thu, 25 Feb 2021 16:23:56 -0500 Subject: [PATCH] We can create a new single-population model --- src/blur.rs | 6 ++-- src/main.rs | 5 ++- src/model.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/blur.rs b/src/blur.rs index 2e384c3..72e8261 100644 --- a/src/blur.rs +++ b/src/blur.rs @@ -63,7 +63,7 @@ impl Blur { for j in 0..radius { value += src_row[width - radius + j] + src_row[j]; } - // At this point "value" contains the unweighted sum for the right-most row element. + for i in 0..width { let left = (i + width - radius - 1) & (width - 1); let right = (i + radius) & (width - 1); @@ -82,7 +82,6 @@ impl Blur { // We don't replicate the horizontal filter logic because of the cache-unfriendly memory // access patterns of sequential iteration over individual columns. Instead, we iterate over // rows via loop interchange. - let offset = (height - radius - 1) * width; self.row_buffer .copy_from_slice(&src[offset..offset + width]); @@ -97,7 +96,6 @@ impl Blur { *buf += bottom + top; } } - // At this point row_buffer contains the unweighted sum for all top elements. for (i, dst_row) in dst.chunks_exact_mut(width).enumerate() { let bottom_off = ((i + height - radius - 1) & (height - 1)) * width; @@ -128,7 +126,7 @@ mod tests { blur.box_blur_h(&src, &mut dst, 1); assert_eq!( dst, - &[ + [ 2.3333335, 2.0, 3.0, 2.6666667, 6.3333335, 6.0, 7.0, 6.666667, 10.333334, 10.0, 11.0, 10.666667, 14.333334, 14.0, 15.0, 14.666667 ] diff --git a/src/main.rs b/src/main.rs index cc44dba..d134d4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,4 +2,7 @@ mod blur; mod grid; mod model; -fn main() {} +fn main() { + let model = model::Model::new(4, 4, 20, 1); + println!("{:#?}", model); +} diff --git a/src/model.rs b/src/model.rs index d4ed288..0b552c0 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,32 +1,97 @@ use crate::grid::Grid; +use rand::{thread_rng, Rng}; + /// A single Physarum agent. The x and y positions are continuous, hence we use floating point /// numbers instead of integers. #[derive(Debug)] -pub struct Agent { - pub x: f32, - pub y: f32, - pub angle: f32, +struct Agent { + x: f32, + y: f32, + angle: f32, +} + +impl Agent { + fn new(width: usize, height: usize) -> Self { + let mut rng = rand::thread_rng(); + let (x, y, angle) = rng.gen::<(f32, f32, f32)>(); + Agent { + x: x * width as f32, + y: y * height as f32, + angle: angle * std::f32::consts::TAU, + } + } } /// A model configuration. We make it into a separate type, because we will eventually have multiple /// configurations in one model. #[derive(Debug)] -pub struct PopulationConfig { - pub sensor_angle: f32, - pub sensor_distance: f32, - pub rotation_angle: f32, - pub step_distance: f32, - pub decay_factor: f32, +struct PopulationConfig { + sensor_distance: f32, + step_distance: f32, + decay_factor: f32, + sensor_angle: f32, + rotation_angle: f32, } -impl PopulationConfig {} +impl PopulationConfig { + const SENSOR_ANGLE_MIN: f32 = 0.0; + const SENSOR_ANGLE_MAX: f32 = 120.0; + const SENSOR_DISTANCE_MIN: f32 = 0.0; + const SENSOR_DISTANCE_MAX: f32 = 64.0; + const ROTATION_ANGLE_MIN: f32 = 0.0; + const ROTATION_ANGLE_MAX: f32 = 120.0; + const STEP_DISTANCE_MIN: f32 = 0.2; + const STEP_DISTANCE_MAX: f32 = 2.0; + const DEPOSITION_AMOUNT_MIN: f32 = 5.0; + const DEPOSITION_AMOUNT_MAX: f32 = 5.0; + const DECAY_FACTOR_MIN: f32 = 0.1; + const DECAY_FACTOR_MAX: f32 = 0.1; + + /// Generate a random configuration. + pub fn new() -> Self { + let mut rng = rand::thread_rng(); + + PopulationConfig { + sensor_distance: rng.gen_range(Self::SENSOR_DISTANCE_MIN..=Self::SENSOR_DISTANCE_MAX), + step_distance: rng.gen_range(Self::STEP_DISTANCE_MIN..=Self::STEP_DISTANCE_MAX), + decay_factor: rng.gen_range(Self::DECAY_FACTOR_MIN..=Self::DECAY_FACTOR_MAX), + sensor_angle: rng + .gen_range(Self::SENSOR_ANGLE_MIN..=Self::SENSOR_ANGLE_MAX) + .to_radians(), + rotation_angle: rng + .gen_range(Self::ROTATION_ANGLE_MIN..=Self::ROTATION_ANGLE_MAX) + .to_radians(), + } + } +} /// Top-level simulation class. #[derive(Debug)] pub struct Model { - grid: Grid, + // Physarum agents. agents: Vec, + // The grid they move on. + grid: Grid, + + // Simulation parameters. + diffusivity: usize, config: PopulationConfig, + + iteration: i32, +} + +impl Model { + pub fn new(width: usize, height: usize, n_particles: usize, diffusivity: usize) -> Self { + Model { + agents: (0..n_particles) + .map(|_| Agent::new(width, height)) + .collect(), + grid: Grid::new(width, height), + diffusivity, + config: PopulationConfig::new(), + iteration: 0, + } + } }