Compare commits

...

5 Commits

3 changed files with 47 additions and 59 deletions

View File

@@ -1,3 +1,4 @@
use crate::grid::PopulationConfig;
use crate::{buffer::Buf, util::wrap}; use crate::{buffer::Buf, util::wrap};
use fastapprox::faster::{cos, sin}; use fastapprox::faster::{cos, sin};
use rand::prelude::IndexedRandom; use rand::prelude::IndexedRandom;
@@ -31,26 +32,17 @@ impl Agent {
} }
/// Tick an agent /// Tick an agent
pub fn tick( pub fn tick(&mut self, buf: &Buf, pop_config: PopulationConfig, width: usize, height: usize) {
&mut self, let xc = self.x + cos(self.heading) * pop_config.sensor_distance;
buf: &Buf, let yc = self.y + sin(self.heading) * pop_config.sensor_distance;
sensor_distance: f32,
sensor_angle: f32,
rotation_angle: f32,
step_distance: f32,
width: usize,
height: usize,
) {
let xc = self.x + cos(self.heading) * sensor_distance;
let yc = self.y + sin(self.heading) * sensor_distance;
let agent_add_sens = self.heading + sensor_angle; let agent_add_sens = self.heading + pop_config.sensor_angle;
let agent_sub_sens = self.heading - sensor_angle; let agent_sub_sens = self.heading - pop_config.sensor_angle;
let xl = self.x + cos(agent_sub_sens) * sensor_distance; let xl = self.x + cos(agent_sub_sens) * pop_config.sensor_distance;
let yl = self.y + sin(agent_sub_sens) * sensor_distance; let yl = self.y + sin(agent_sub_sens) * pop_config.sensor_distance;
let xr = self.x + cos(agent_add_sens) * sensor_distance; let xr = self.x + cos(agent_add_sens) * pop_config.sensor_distance;
let yr = self.y + sin(agent_add_sens) * sensor_distance; let yr = self.y + sin(agent_add_sens) * pop_config.sensor_distance;
// We sense from the buffer because this is where we previously combined data from all the grid. // We sense from the buffer because this is where we previously combined data from all the grid.
let center = buf.get_buf(xc, yc); let center = buf.get_buf(xc, yc);
@@ -72,10 +64,16 @@ impl Agent {
0.0 0.0
}; };
let delta_angle = rotation_angle * direction; let delta_angle = pop_config.rotation_angle * direction;
self.heading = wrap(self.heading + delta_angle, TAU); self.heading = wrap(self.heading + delta_angle, TAU);
self.x = wrap(self.x + step_distance * cos(self.heading), width as f32); self.x = wrap(
self.y = wrap(self.y + step_distance * sin(self.heading), height as f32); self.x + pop_config.step_distance * cos(self.heading),
width as f32,
);
self.y = wrap(
self.y + pop_config.step_distance * sin(self.heading),
height as f32,
);
} }
} }

View File

@@ -7,10 +7,10 @@ use std::fmt::{Display, Formatter};
/// A population configuration. /// A population configuration.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct PopulationConfig { pub struct PopulationConfig {
sensor_distance: f32, pub sensor_distance: f32,
step_distance: f32, pub step_distance: f32,
sensor_angle: f32, pub sensor_angle: f32,
rotation_angle: f32, pub rotation_angle: f32,
deposition_amount: f32, deposition_amount: f32,
} }
@@ -90,25 +90,8 @@ impl Grid {
} }
pub fn tick(&mut self) { pub fn tick(&mut self) {
let (width, height) = (self.width, self.height);
let PopulationConfig {
sensor_distance,
sensor_angle,
rotation_angle,
step_distance,
..
} = self.config;
self.agents.par_iter_mut().for_each(|agent| { self.agents.par_iter_mut().for_each(|agent| {
agent.tick( agent.tick(&self.buf, self.config, self.width, self.height);
&self.buf,
sensor_distance,
sensor_angle,
rotation_angle,
step_distance,
width,
height,
);
}); });
self.deposit_all(); self.deposit_all();
} }
@@ -131,11 +114,14 @@ where
// We mutate grid buffers and read grid data. We use unsafe because we need shared/unique borrows on different fields of the same Grid struct. // We mutate grid buffers and read grid data. We use unsafe because we need shared/unique borrows on different fields of the same Grid struct.
bufs.iter().enumerate().for_each(|(i, buf)| { bufs.iter().enumerate().for_each(|(i, buf)| {
let buf_ptr = *buf as *const Vec<f32> as *mut Vec<f32>; let buf_ptr = *buf as *const Vec<f32> as *mut Vec<f32>;
unsafe { buf_ptr.as_mut() }.unwrap().fill(0.0); // SAFETY! we can take these are raw pointers because we are
// getting it from a `&mut [Grid]`
let buf_ptr_mut = unsafe { buf_ptr.as_mut().unwrap_unchecked() };
buf_ptr_mut.fill(0.0);
datas.iter().enumerate().for_each(|(j, other)| { datas.iter().enumerate().for_each(|(j, other)| {
let multiplier = attraction_table[i].as_ref()[j]; let multiplier = attraction_table[i].as_ref()[j];
unsafe { buf_ptr.as_mut() } buf_ptr_mut
.unwrap()
.iter_mut() .iter_mut()
.zip(*other) .zip(*other)
.for_each(|(to, from)| *to += from * multiplier) .for_each(|(to, from)| *to += from * multiplier)

View File

@@ -57,28 +57,32 @@ impl Model {
let attraction_distr = let attraction_distr =
Normal::new(Self::ATTRACTION_FACTOR_MEAN, Self::ATTRACTION_FACTOR_STD).unwrap(); Normal::new(Self::ATTRACTION_FACTOR_MEAN, Self::ATTRACTION_FACTOR_STD).unwrap();
let repulstion_distr = let repulsion_distr =
Normal::new(Self::REPULSION_FACTOR_MEAN, Self::REPULSION_FACTOR_STD).unwrap(); Normal::new(Self::REPULSION_FACTOR_MEAN, Self::REPULSION_FACTOR_STD).unwrap();
let mut attraction_table = Vec::with_capacity(n_populations); let mut attraction_table = Vec::with_capacity(n_populations);
for i in 0..n_populations { for i in 0..n_populations {
attraction_table.push(Vec::with_capacity(n_populations)); attraction_table.push(Vec::with_capacity(n_populations));
for j in 0..n_populations { for j in 0..n_populations {
attraction_table[i].push(if i == j { attraction_table[i].push(
attraction_distr.sample(&mut rng) if i == j {
&attraction_distr
} else { } else {
repulstion_distr.sample(&mut rng) &repulsion_distr
}); }
.sample(&mut rng),
);
} }
} }
let mut grids: Vec<Grid> = Vec::new(); let grids = (0..n_populations)
for _ in 0..n_populations { .map(|_| {
let agents = (0..particles_per_grid) let agents = (0..particles_per_grid)
.map(|_| Agent::new(width, height, &mut rng)) .map(|_| Agent::new(width, height, &mut rng))
.collect(); .collect();
grids.push(Grid::new(width, height, &mut rng, agents)); Grid::new(width, height, &mut rng, agents)
} })
.collect();
Model { Model {
population_grids: grids, population_grids: grids,