cisat/abm/
cohort.rs

1//! This module contains the Cohort class, a container for multiple Teams.
2
3use super::{
4    super::utilities::{parameters::Parameters, Solution},
5    agent::{Agent, AgentMethods},
6    team::{Team, TeamMethods},
7};
8use crate::problems::Ackley;
9use rayon::prelude::*;
10use std::marker::PhantomData;
11
12/// This is the Cohort class, a container for multiple teams
13///
14/// The cohort allows you to run a set of teams easily to achieve statistical significance:
15/// ```
16/// use cisat::{Parameters, Cohort, problems::Ackley};
17/// let mut x = Cohort::<Ackley>::new(Parameters::default());
18/// x.solve();
19/// ```
20///Above, we specify one generic parameters `Ackley`, which tells the `Cohort` which problem to solve.
21/// However, we can get more complciated than that! For instance, we feed in a struct that implements
22/// `AgentMethods` to specific which type of agent to use:
23/// ```
24/// use cisat::{Parameters, Cohort, problems::Ackley, Agent};
25/// let mut x = Cohort::<Ackley, Agent<Ackley>>::new(Parameters::default());
26/// x.solve();
27/// ```
28/// Here, we just fed in the in-build `Agent` class which already implements `AgentMethods`. You can
29/// implement the trait yourself to define a new agent though. The same applies for 'Team' and
30/// 'TeamMethods':
31/// ```
32/// use cisat::{Parameters, Cohort, problems::Ackley, Agent, Team};
33/// let mut x = Cohort::<Ackley, Agent<Ackley>, Team<Ackley, Agent<Ackley>>>::new(Parameters::default());
34/// x.solve();
35/// ```
36
37#[derive(Clone, Debug)]
38pub struct Cohort<S = Ackley, A = Agent<S>, T = Team<S, A>>
39where
40    S: Solution,
41    A: AgentMethods<S>,
42    T: TeamMethods<S, A>,
43{
44    /// This contains the parameters for the class
45    parameters: Parameters,
46    /// This contains the teams in the cohort
47    team_list: Vec<T>,
48    /// Bookkeeping the solution type
49    solution_type: PhantomData<S>,
50    /// Bookkeeping the agent-type
51    agent_type: PhantomData<A>,
52}
53
54impl<S, A, T> Cohort<S, A, T>
55where
56    S: Solution,
57    A: AgentMethods<S>,
58    T: TeamMethods<S, A>,
59{
60    /// This generates a new cohort
61    pub fn new(parameters: Parameters) -> Cohort<S, A, T> {
62        Cohort {
63            team_list: (0..parameters.number_of_teams)
64                .map(|_| T::new(parameters.clone()))
65                .collect(),
66            solution_type: Default::default(),
67            parameters,
68            agent_type: Default::default(),
69        }
70    }
71
72    /// This runs the cohort using parallelism
73    pub fn solve(&mut self) {
74        self.team_list.par_iter_mut().for_each(|x| x.solve());
75    }
76
77    /// This runs a single iteration
78    pub fn iterate(&mut self) {
79        self.team_list.iter_mut().for_each(|x| x.iterate());
80    }
81
82    /// Get the current best solution
83    pub fn get_best_solution_so_far(&mut self) -> f64 {
84        (0..self.parameters.number_of_teams)
85            .map(|i| self.team_list[i].get_best_solution_so_far())
86            .collect::<Vec<S>>()
87            .into_iter()
88            .max()
89            .unwrap()
90            .get_quality_scalar()
91    }
92}
93
94impl Default for Cohort {
95    fn default() -> Self {
96        Cohort::new(Default::default())
97    }
98}