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(())
    }
}