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}