1#![warn(missing_docs)]
2#![allow(clippy::needless_doctest_main)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5#[cfg_attr(docsrs, doc(cfg(feature = "builtin")))]
9#[cfg(feature = "builtin")]
10pub mod builtin;
11
12pub mod prelude;
15
16#[cfg(feature = "rayon")]
17use rayon::prelude::*;
18
19#[cfg(feature = "tracing")]
20use tracing::*;
21
22#[cfg(feature = "tracing")]
23#[allow(missing_docs)]
24pub trait Rng: rand::Rng + std::fmt::Debug {}
25
26#[cfg(feature = "tracing")]
27impl<T: rand::Rng + std::fmt::Debug> Rng for T {}
28
29#[cfg(not(feature = "tracing"))]
30#[allow(missing_docs)]
31pub trait Rng: rand::Rng {}
32
33#[cfg(not(feature = "tracing"))]
34impl<T: rand::Rng> Rng for T {}
35
36pub trait Eliminator<G> {
38 fn eliminate(&self, genomes: Vec<G>) -> Vec<G>;
40}
41
42pub trait Repopulator<G> {
44 fn repopulate(&self, genomes: &mut Vec<G>, target_size: usize);
46}
47
48#[cfg(not(feature = "rayon"))]
51pub trait FeatureBoundedEliminator<G>: Eliminator<G> {}
52#[cfg(not(feature = "rayon"))]
53impl<G, T: Eliminator<G>> FeatureBoundedEliminator<G> for T {}
54
55#[cfg(feature = "rayon")]
58pub trait FeatureBoundedEliminator<G>: Eliminator<G> + Send + Sync {}
59#[cfg(feature = "rayon")]
60impl<G, T: Eliminator<G> + Send + Sync> FeatureBoundedEliminator<G> for T {}
61
62#[cfg(not(feature = "rayon"))]
65pub trait FeatureBoundedRepopulator<G>: Repopulator<G> {}
66#[cfg(not(feature = "rayon"))]
67impl<G, T: Repopulator<G>> FeatureBoundedRepopulator<G> for T {}
68
69#[cfg(feature = "rayon")]
72pub trait FeatureBoundedRepopulator<G>: Repopulator<G> + Send + Sync {}
73#[cfg(feature = "rayon")]
74impl<G, T: Repopulator<G> + Send + Sync> FeatureBoundedRepopulator<G> for T {}
75
76#[cfg(not(feature = "rayon"))]
79pub trait FeatureBoundedGenome {}
80#[cfg(not(feature = "rayon"))]
81impl<T> FeatureBoundedGenome for T {}
82
83#[cfg(feature = "rayon")]
86pub trait FeatureBoundedGenome: Sized + Send + Sync {}
87#[cfg(feature = "rayon")]
88impl<T: Sized + Send + Sync> FeatureBoundedGenome for T {}
89
90pub struct GeneticSim<G: Sized, E: FeatureBoundedEliminator<G>, R: FeatureBoundedRepopulator<G>> {
93 pub genomes: Vec<G>,
95
96 pub eliminator: E,
98
99 pub repopulator: R,
101}
102
103impl<G, E, R> GeneticSim<G, E, R>
104where
105 G: Sized,
106 E: FeatureBoundedEliminator<G>,
107 R: FeatureBoundedRepopulator<G>,
108{
109 pub fn new(starting_genomes: Vec<G>, eliminator: E, repopulator: R) -> Self {
112 Self {
113 genomes: starting_genomes,
114 eliminator,
115 repopulator,
116 }
117 }
118
119 pub fn next_generation(&mut self) {
121 #[cfg(feature = "tracing")]
122 let span = span!(Level::TRACE, "next_generation");
123
124 #[cfg(feature = "tracing")]
125 let enter = span.enter();
126
127 let genomes = std::mem::take(&mut self.genomes);
128
129 let target_size = genomes.len();
130 self.genomes = self.eliminator.eliminate(genomes);
131 self.repopulator.repopulate(&mut self.genomes, target_size);
132
133 #[cfg(feature = "tracing")]
134 drop(enter);
135 }
136
137 pub fn perform_generations(&mut self, count: usize) {
139 for _ in 0..count {
140 self.next_generation();
141 }
142 }
143}
144
145#[cfg(feature = "genrand")]
147#[cfg_attr(docsrs, doc(cfg(feature = "genrand")))]
148pub trait GenerateRandom {
149 fn gen_random(rng: &mut impl Rng) -> Self;
151}
152
153#[cfg(all(feature = "genrand", not(feature = "rayon")))]
155#[cfg_attr(docsrs, doc(cfg(feature = "genrand")))]
156pub trait GenerateRandomCollection<T>
157where
158 T: GenerateRandom,
159{
160 fn gen_random(rng: &mut impl Rng, amount: usize) -> Self;
162}
163
164#[cfg(all(feature = "genrand", feature = "rayon"))]
166pub trait GenerateRandomCollection<T>
167where
168 T: GenerateRandom + Send,
169{
170 fn gen_random(amount: usize) -> Self;
172}
173
174#[cfg(not(feature = "rayon"))]
175impl<C, T> GenerateRandomCollection<T> for C
176where
177 C: FromIterator<T>,
178 T: GenerateRandom,
179{
180 #[cfg_attr(feature = "tracing", instrument)]
181 fn gen_random(rng: &mut impl Rng, amount: usize) -> Self {
182 (0..amount).map(|_| T::gen_random(rng)).collect()
183 }
184}
185
186#[cfg(feature = "rayon")]
187impl<C, T> GenerateRandomCollection<T> for C
188where
189 C: FromParallelIterator<T>,
190 T: GenerateRandom + Send,
191{
192 #[cfg_attr(feature = "tracing", instrument)]
193 fn gen_random(amount: usize) -> Self {
194 (0..amount)
195 .into_par_iter()
196 .map(|_| T::gen_random(&mut rand::rng()))
197 .collect()
198 }
199}