store agents in grids, not model
This commit is contained in:
parent
4e688c3fa7
commit
953c540263
10
src/grid.rs
10
src/grid.rs
@ -1,4 +1,7 @@
|
||||
use crate::blur::Blur;
|
||||
use crate::{
|
||||
blur::Blur,
|
||||
model::Agent,
|
||||
};
|
||||
|
||||
use rand::{distributions::Uniform, Rng};
|
||||
|
||||
@ -88,6 +91,7 @@ pub struct Grid {
|
||||
// Scratch space for the blur operation.
|
||||
buf: Vec<f32>,
|
||||
blur: Blur,
|
||||
pub agents: Vec<Agent>
|
||||
}
|
||||
|
||||
impl Clone for Grid {
|
||||
@ -99,13 +103,14 @@ impl Clone for Grid {
|
||||
data: self.data.clone(),
|
||||
buf: self.buf.clone(),
|
||||
blur: self.blur.clone(),
|
||||
agents: self.agents.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
// Create a new grid filled with random floats in the [0.0..1.0) range.
|
||||
pub fn new<R: Rng + ?Sized>(width: usize, height: usize, rng: &mut R) -> Self {
|
||||
pub fn new<R: Rng + ?Sized>(width: usize, height: usize, rng: &mut R, agents: Vec<Agent>) -> Self {
|
||||
if !width.is_power_of_two() || !height.is_power_of_two() {
|
||||
panic!("Grid dimensions must be a power of two.");
|
||||
}
|
||||
@ -119,6 +124,7 @@ impl Grid {
|
||||
config: PopulationConfig::new(rng),
|
||||
buf: vec![0.0; width * height],
|
||||
blur: Blur::new(width),
|
||||
agents,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@ -2,15 +2,15 @@ use physarum::model;
|
||||
|
||||
fn main() {
|
||||
// # of iterations to go through
|
||||
let n_iterations = 2048;
|
||||
let n_iterations = 254;
|
||||
|
||||
// Size of grid and pictures
|
||||
// let (width, height) = (256, 256);
|
||||
let (width, height) = (1024, 1024);
|
||||
let (width, height) = (256, 256);
|
||||
// let (width, height) = (1024, 1024);
|
||||
|
||||
// # of agents
|
||||
let n_particles = 1 << 24;
|
||||
// let n_particles = 1 << 16;
|
||||
// let n_particles = 1 << 24;
|
||||
let n_particles = 1 << 16;
|
||||
println!("n_particles: {}", n_particles);
|
||||
|
||||
let diffusivity = 1;
|
||||
|
||||
141
src/model.rs
141
src/model.rs
@ -14,7 +14,7 @@ use std::{f32::consts::TAU, path::Path, time::Instant};
|
||||
|
||||
// A single Physarum agent. The x and y positions are continuous, hence we use floating point numbers instead of integers.
|
||||
#[derive(Debug)]
|
||||
struct Agent {
|
||||
pub struct Agent {
|
||||
x: f32,
|
||||
y: f32,
|
||||
angle: f32,
|
||||
@ -34,6 +34,60 @@ impl Agent {
|
||||
i,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn tick(&mut self, grid: &Grid) {
|
||||
let (width, height) = (grid.width, grid.height);
|
||||
let PopulationConfig {
|
||||
sensor_distance,
|
||||
sensor_angle,
|
||||
rotation_angle,
|
||||
step_distance,
|
||||
..
|
||||
} = grid.config;
|
||||
|
||||
let xc = self.x + fastapprox::faster::cos(self.angle) * sensor_distance;
|
||||
let yc = self.y + fastapprox::faster::sin(self.angle) * sensor_distance;
|
||||
|
||||
let agent_add_sens = self.angle + sensor_angle;
|
||||
let agent_sub_sens = self.angle - sensor_angle;
|
||||
|
||||
let xl = self.x + fastapprox::faster::cos(agent_sub_sens) * sensor_distance;
|
||||
let yl = self.y + fastapprox::faster::sin(agent_sub_sens) * sensor_distance;
|
||||
let xr = self.x + fastapprox::faster::cos(agent_add_sens) * sensor_distance;
|
||||
let yr = self.y + fastapprox::faster::sin(agent_add_sens) * sensor_distance;
|
||||
|
||||
// We sense from the buffer because this is where we previously combined data from all the grid.
|
||||
let center = grid.get_buf(xc, yc);
|
||||
let left = grid.get_buf(xl, yl);
|
||||
let right = grid.get_buf(xr, yr);
|
||||
|
||||
// Rotate and move logic
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut direction: f32 = 0.0;
|
||||
|
||||
if (center > left) && (center > right) {
|
||||
direction = 0.0;
|
||||
} else if (center < left) && (center < right) {
|
||||
direction = *[-1.0, 1.0].choose(&mut rng).unwrap();
|
||||
} else if left < right {
|
||||
direction = 1.0;
|
||||
} else if right < left {
|
||||
direction = -1.0;
|
||||
}
|
||||
|
||||
let delta_angle = rotation_angle * direction;
|
||||
|
||||
self.angle = wrap(self.angle + delta_angle, TAU);
|
||||
self.x = wrap(
|
||||
self.x + step_distance * fastapprox::faster::cos(self.angle),
|
||||
width as f32,
|
||||
);
|
||||
self.y = wrap(
|
||||
self.y + step_distance * fastapprox::faster::sin(self.angle),
|
||||
height as f32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Agent {
|
||||
@ -61,7 +115,7 @@ impl PartialEq for Agent {
|
||||
// Top-level simulation class.
|
||||
pub struct Model {
|
||||
// Physarum agents.
|
||||
agents: Vec<Agent>,
|
||||
// agents: Vec<Agent>,
|
||||
|
||||
// The grid they move on.
|
||||
grids: Vec<Grid>,
|
||||
@ -125,13 +179,15 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
let mut grids: Vec<Grid> = Vec::new();
|
||||
for _ in (0..n_populations) {
|
||||
let agents = (0..particles_per_grid)
|
||||
.map(|i| Agent::new(width, height, i / particles_per_grid, &mut rng, i)).collect();
|
||||
grids.push(Grid::new(width, height, &mut rng, agents));
|
||||
|
||||
}
|
||||
Model {
|
||||
agents: (0..(n_particles-1))
|
||||
.map(|i| Agent::new(width, height, i / particles_per_grid, &mut rng, i))
|
||||
.collect(),
|
||||
grids: (0..n_populations)
|
||||
.map(|_| Grid::new(width, height, &mut rng))
|
||||
.collect(),
|
||||
grids,
|
||||
attraction_table,
|
||||
diffusivity,
|
||||
iteration: 0,
|
||||
@ -157,6 +213,7 @@ impl Model {
|
||||
let mut time_per_agent_list: Vec<f64> = Vec::new();
|
||||
let mut time_per_step_list: Vec<f64> = Vec::new();
|
||||
|
||||
let agents_num: usize = self.grids.iter().map(|grid| grid.agents.len()).sum();
|
||||
for i in 0..steps {
|
||||
if debug {
|
||||
println!("Starting tick for all agents...")
|
||||
@ -165,67 +222,23 @@ impl Model {
|
||||
// Combine grids
|
||||
let grids = &mut self.grids;
|
||||
combine(grids, &self.attraction_table);
|
||||
let grids_immutable_1 = &grids.clone();
|
||||
|
||||
let agents_tick_time = Instant::now();
|
||||
|
||||
// Tick agents
|
||||
self.agents.par_iter_mut().for_each(|agent| {
|
||||
let grid = &grids[agent.population_id];
|
||||
let (width, height) = (grid.width, grid.height);
|
||||
let PopulationConfig {
|
||||
sensor_distance,
|
||||
sensor_angle,
|
||||
rotation_angle,
|
||||
step_distance,
|
||||
..
|
||||
} = grid.config;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut direction: f32 = 0.0;
|
||||
|
||||
let agent_add_sens = agent.angle + sensor_angle;
|
||||
let agent_sub_sens = agent.angle - sensor_angle;
|
||||
|
||||
let xl = agent.x + fastapprox::faster::cos(agent_sub_sens) * sensor_distance;
|
||||
let yl = agent.y + fastapprox::faster::sin(agent_sub_sens) * sensor_distance;
|
||||
let left = grid.get_buf(xl, yl);
|
||||
|
||||
let xr = agent.x + fastapprox::faster::cos(agent_add_sens) * sensor_distance;
|
||||
let yr = agent.y + fastapprox::faster::sin(agent_add_sens) * sensor_distance;
|
||||
let right = grid.get_buf(xr, yr);
|
||||
|
||||
let xc = agent.x + fastapprox::faster::cos(agent.angle) * sensor_distance;
|
||||
let yc = agent.y + fastapprox::faster::sin(agent.angle) * sensor_distance;
|
||||
let center = grid.get_buf(xc, yc);
|
||||
// println!("{} {} {}", right, left, center);
|
||||
|
||||
// Rotate and move logic
|
||||
if (center > left) && (center > right) {
|
||||
direction = 0.0;
|
||||
} else if (center < left) && (center < right) {
|
||||
direction = *[-1.0, 1.0].choose(&mut rng).unwrap();
|
||||
} else if left < right {
|
||||
direction = 1.0;
|
||||
} else if right < left {
|
||||
direction = -1.0;
|
||||
}
|
||||
|
||||
let delta_angle = rotation_angle * direction;
|
||||
|
||||
agent.angle = wrap(agent.angle + delta_angle, TAU);
|
||||
agent.x = wrap(
|
||||
agent.x + step_distance * fastapprox::faster::cos(agent.angle),
|
||||
width as f32,
|
||||
);
|
||||
agent.y = wrap(
|
||||
agent.y + step_distance * fastapprox::faster::sin(agent.angle),
|
||||
height as f32,
|
||||
);
|
||||
});
|
||||
for grid in grids.iter_mut() {
|
||||
grid.agents.par_iter_mut().for_each(|agent| {
|
||||
agent.tick(&grids_immutable_1[agent.population_id]);
|
||||
});
|
||||
}
|
||||
|
||||
// Deposit
|
||||
for agent in self.agents.iter() {
|
||||
self.grids[agent.population_id].deposit(agent.x, agent.y);
|
||||
let grids_immutable_2 = &grids.clone();
|
||||
for grid in grids_immutable_2.iter() {
|
||||
for agent in grid.agents.iter() {
|
||||
self.grids[agent.population_id].deposit(agent.x, agent.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Diffuse + Decay
|
||||
@ -237,7 +250,7 @@ impl Model {
|
||||
self.save_image_data();
|
||||
|
||||
let agents_tick_elapsed: f64 = agents_tick_time.elapsed().as_millis() as f64;
|
||||
let ms_per_agent: f64 = (agents_tick_elapsed as f64) / (self.agents.len() as f64);
|
||||
let ms_per_agent: f64 = (agents_tick_elapsed as f64) / (agents_num as f64);
|
||||
time_per_agent_list.push(ms_per_agent);
|
||||
time_per_step_list.push(agents_tick_elapsed);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user