You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

80 lines
2.1 KiB

use rand::Rng;
use rayon::prelude::*;
pub struct Arena<T: Genetic> {
pub keep: usize,
pub mutate: usize,
pub crossover: usize,
pub set: Vec<T>,
pub config: T::Configuration,
}
impl<T: Genetic> Arena<T> {
pub fn new<R: Rng>(rng: &mut R, keep: usize, mutate: usize, crossover: usize, config: T::Configuration) -> Self {
let mut set = Vec::new();
for _ in 0..keep {
set.push(T::generate(rng, &config));
}
Arena {
keep,
mutate,
crossover,
set,
config,
}
}
pub fn generate<R: Rng>(&mut self, rng: &mut R) {
let n = self.set.len();
for _ in 0..self.mutate {
let which = rng.gen_range(0..n);
let mutant = self.set[which].mutate(rng, &self.config);
self.set.push(mutant);
}
for _ in 0..self.crossover {
let p1 = rng.gen_range(0..n);
let p2 = rng.gen_range(0..n);
let child = self.set[p1].crossover(rng, &self.set[p2], &self.config);
self.set.push(child);
}
}
pub fn cull<R: Rng>(&mut self, rng: &mut R) {
let config = &self.config;
let set = &mut self.set;
set.sort_by(|a, b| a.compare(rng, b, config));
self.set.truncate(self.keep);
}
}
impl <T: Genetic> Arena<T> where
T: Send + Sync,
T::Configuration: Sync,
{
pub fn par_process<F: Fn(&mut T, &T::Configuration) + Sync>(&mut self, f: F) {
let config = &self.config;
self.set.par_iter_mut().for_each(|x| f(x, config));
}
}
impl<T: Genetic> Arena<T> where
T: Send,
T::Configuration: Sync,
{
pub fn par_cull(&mut self) {
let config = &self.config;
let set = &mut self.set;
set.par_sort_unstable_by(|a, b| a.compare(&mut rand::thread_rng(), b, config));
self.set.truncate(self.keep);
}
}
pub trait Genetic {
type Configuration;
fn generate<R: Rng>(rng: &mut R, config: &Self::Configuration) -> Self;
fn mutate<R: Rng>(&self, rng: &mut R, config: &Self::Configuration) -> Self;
fn crossover<R: Rng>(&self, rng: &mut R, other: &Self, config: &Self::Configuration) -> Self;
fn compare<R: Rng>(&self, rng: &mut R, other: &Self, config: &Self::Configuration) -> std::cmp::Ordering;
}