1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
//! This module will hold all the main functions that should be called. The specific order is
//! recommended but some functions depend on the build up or tear down of others.
//!
//! The following order order of operations is recommended:
//!
//! # Example
//! ```
//! use sim_rust::Agent;
//! use sim_rust::functions::*;
//!
//! // method 1 and 2 have the exact same outcome
//!
//! // method 1
//! let mut env_1 = generate_default_env::<ExampleAgent1>(10).unwrap();
//! env_1 = tick(env_1).unwrap(); //(or tick_collect)
//! collect(env_1);
//!
//!
//! // method 2
//! let mut env_2 = generate_default_tick_collect::<ExampleAgent1>(10, 1, 1).unwrap();
//!
//!
//! // method 3
//! let mut env_3 = generate_default_env::<ExampleAgent1>(10).unwrap();
//! // Any type that implements the Agent trait can be added to the environment.
//! let example_agent_2 = ExampleAgent2::generate().unwrap();
//! env_3.add_agent(example_agent_2).unwrap();
//! // even mulitple instances at once.
//! let example_agents: Vec<Box<dyn Agent>> = vec![
//! ExampleAgent2::generate().unwrap(),
//! ExampleAgent2::generate().unwrap(),
//! ExampleAgent2::generate().unwrap(),
//! ];
//! env_3.add_agents(example_agents).unwrap();
//! env_3 = tick(env_3).unwrap();
//! collect(env_3);
//!
//!
//! // This is just a very simple implementation of an agent.
//! struct ExampleAgent1 {
//! age: u8,
//! }
//!
//! struct ExampleAgent2 {
//! age: u8,
//! }
//!
//!
//! impl Agent for ExampleAgent1 {
//! fn generate() -> Result<Box<Self> ,&'static str> {
//! let agent = Box::new(Self {age: 1});
//! Ok(agent)
//! }
//!
//! fn tick(&mut self) -> Result<(), &'static str> {
//! self.age += 1;
//! Ok(())
//! }
//!
//! fn collect(&self) -> Result<(), &'static str> {
//! Ok(())
//! }
//! }
//!
//! // This is a direct copy of the implementation of ExampleAgent1
//! impl Agent for ExampleAgent2 {
//! fn generate() -> Result<Box<Self> ,&'static str> {
//! let agent = Box::new(Self {age: 1});
//! Ok(agent)
//! }
//!
//! fn tick(&mut self) -> Result<(), &'static str> {
//! self.age += 1;
//! Ok(())
//! }
//!
//! fn collect(&self) -> Result<(), &'static str> {
//! Ok(())
//! }
//! }
//!```
use std::thread;
use crate::traits::{Environment, Agent};
/// Generates a standard environment with a specified agent.
/// This environment is the standard implementation and does
/// not provide any custom behavior.
pub fn generate_default_env<A: 'static + Agent>(pop_size: u64) -> Result<Box<dyn Environment>, &'static str> {
let mut pop: Vec<Box<dyn Agent>> = vec!();
for _ in 0..pop_size {
let agent: Box<dyn Agent> = A::generate()?;
pop.push(agent);
}
let env: Box<DefaultEnvironment> = DefaultEnvironment::generate(pop)?;
Ok(env)
}
/// Applies a tick to a passed in environment. This takes both
/// the default environment provided by this library and custom
/// defined environments created by the user.
pub fn tick(mut environment: Box<dyn Environment>) -> Result<Box<dyn Environment>, &'static str> {
(*environment).tick()?;
Ok(environment)
}
/// Applies a tick and a collent to a passed in environment.
/// This takes both the default environment provided by this
/// library and custom defined environments created by the user.
/// This function can be used when the user requies data from a
/// certain time in a running simulation.
pub fn tick_collect(mut environment: Box<dyn Environment>) -> Result<Box<dyn Environment>, &'static str> {
(*environment).tick()?;
(*environment).collect()?;
Ok(environment)
}
/// Applies a collect to a passed in environment. This takes both
/// the default environment provided by this library and custom
/// defined environments created by the user.
pub fn collect(environment: Box<dyn Environment>) -> Result<Box<dyn Environment>, &'static str> {
(*environment).collect()?;
Ok(environment)
}
/// Generates an environment and runs it the simulation in multiple
/// processes. This also runs the generated simulation with the
/// given parameters.
pub fn generate_default_tick_collect<A: 'static + Agent>(pop_size: u64, ticks: u64, runs: u64) -> Result<(), &'static str> {
let cpu_count: u64 = num_cpus::get() as u64;
for _ in 0..(runs / cpu_count + 1) {
let mut v = vec!();
for _ in 0..cpu_count {
v.push(thread::spawn(move || -> Result<(), &'static str> {
let mut env = generate_default_env::<A>(pop_size)?;
for _ in 0..ticks {
env = tick(env)?;
}
collect(env)?;
Ok(())
}));
}
for handle in v {
handle.join().unwrap().unwrap();
}
}
Ok(())
}
/// Generates a custom environment specified agent. This environment
/// is the standard implementation and does not provide any custom
/// behavior.
pub fn generate_env<E:'static + Environment, A: 'static + Agent>(pop_size: u64) -> Result<Box<dyn Environment>, &'static str> {
let mut pop: Vec<Box<dyn Agent>> = vec!();
for _ in 0..pop_size {
let agent: Box<dyn Agent> = A::generate()?;
pop.push(agent);
}
let env: Box<E> = E::generate(pop)?;
Ok(env)
}
/// Generates a custom environment and runs it the simulation in
/// multiple processes. This also runs the generated simulation
/// with the given parameters.
pub fn generate_tick_collect<E: 'static + Environment, A: 'static + Agent>(pop_size: u64, ticks: u64, runs: u64) -> Result<(), &'static str> {
let cpu_count: u64 = num_cpus::get() as u64;
for _ in 0..(runs / cpu_count + 1) {
let mut v = vec!();
for _ in 0..cpu_count {
v.push(thread::spawn(move || -> Result<(), &'static str> {
let mut env = generate_env::<E, A>(pop_size)?;
for _ in 0..ticks {
env = tick(env)?;
}
collect(env)?;
Ok(())
}));
}
for handle in v {
handle.join().unwrap().unwrap();
}
}
Ok(())
}
/// A default struct that is used in the default functions.
struct DefaultEnvironment {
population: Vec<Box<dyn Agent>>
}
impl Environment for DefaultEnvironment {
fn generate(population: Vec<Box<dyn Agent>>) -> Result<Box<Self>, &'static str> {
Ok(Box::new(Self {population}))
}
fn collect(&self) -> Result<(), &'static str> {
for agent in &self.population {
(*agent).collect()?;
}
Ok(())
}
fn tick(&mut self) -> Result<(), &'static str> {
let mut pop: Vec<Box<dyn Agent>> = vec!();
for _ in 0..self.population.len() {
let mut agent: Box<dyn Agent> = self.population.pop().unwrap();
agent.tick()?;
pop.push(agent);
}
self.population = pop;
Ok(())
}
fn add_agent(&mut self, agent: Box<dyn Agent>) -> Result<(), &'static str> {
self.population.push(agent);
Ok(())
}
fn add_agents(&mut self, agents: Vec<Box<dyn Agent>>) -> Result<() , &'static str> {
for agent in agents {
self.population.push(agent);
}
Ok(())
}
}