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
//! 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};


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