Compare commits
5 Commits
ec7cce80b4
...
47e09571fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
47e09571fc
|
|||
|
16887c9712
|
|||
|
effe506b45
|
|||
|
492c527498
|
|||
|
b8f1e28eed
|
40
src/agent.rs
40
src/agent.rs
@@ -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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/grid.rs
36
src/grid.rs
@@ -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)
|
||||||
|
|||||||
30
src/model.rs
30
src/model.rs
@@ -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 {
|
||||||
} else {
|
&attraction_distr
|
||||||
repulstion_distr.sample(&mut rng)
|
} else {
|
||||||
});
|
&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,
|
||||||
|
|||||||
Reference in New Issue
Block a user