We can create a new single-population model

This commit is contained in:
mindv0rtex 2021-02-25 16:23:56 -05:00
parent bb1b5ddac0
commit 6a2d19e984
3 changed files with 83 additions and 17 deletions

View File

@ -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
]

View File

@ -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);
}

View File

@ -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<Agent>,
// 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,
}
}
}