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