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
//! 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::<ExampleAgent>(10).unwrap();
//! env_1 = tick(env_1).unwrap(); //(or tick_collect)
//! collect(env_1);
//!
//! //method 2
//! let mut env_2 = generate_default_tick_collect::<ExampleAgent>(10, 1, 1).unwrap();
//!
//!
//!
//! // This is just a very simple implementation of an agent.
//! struct ExampleAgent {
//! age: u8,
//! }
//!
//! impl Agent for ExampleAgent {
//! 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, DefaultEnvironment};
/// 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(())
}