use crate::{
genetic::Genotype,
random::{get_rng, random_seed, Prng, Rng, Seed},
};
use rand::distributions::uniform::SampleUniform;
#[cfg(not(target_arch = "wasm32"))]
use rayon;
use std::{fmt::Debug, marker::PhantomData};
#[derive(Clone, Debug, PartialEq)]
pub struct Population<G>
where
G: Genotype,
{
individuals: Vec<G>,
}
impl<G> Population<G>
where
G: Genotype,
{
pub fn with_individuals(individuals: Vec<G>) -> Population<G> {
Population { individuals }
}
pub fn individuals(&self) -> &[G] {
&self.individuals
}
pub fn size(&self) -> usize {
self.individuals.len()
}
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct PopulationBuilder;
#[cfg(not(target_arch = "wasm32"))]
impl PopulationBuilder {
fn build_population<B, G>(genome_builder: &B, size: usize, mut rng: Prng) -> Population<G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
if size < 50 {
Population {
individuals: (0..size)
.map(|index| genome_builder.build_genome(index, &mut rng))
.collect(),
}
} else {
rng.jump();
let rng1 = rng.clone();
rng.jump();
let rng2 = rng.clone();
let left_size = size / 2;
let right_size = size - left_size;
let (left_population, right_population) = rayon::join(
|| Self::build_population(genome_builder, left_size, rng1),
|| Self::build_population(genome_builder, right_size, rng2),
);
let mut right_individuals = right_population.individuals;
let mut individuals = left_population.individuals;
individuals.append(&mut right_individuals);
Population { individuals }
}
}
}
#[cfg(target_arch = "wasm32")]
impl PopulationBuilder {
fn build_population<B, G>(genome_builder: &B, size: usize, mut rng: Prng) -> Population<G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
Population {
individuals: (0..size)
.map(|index| genome_builder.build_genome(index, &mut rng))
.collect(),
}
}
}
pub trait GenomeBuilder<G>: Sync
where
G: Genotype,
{
fn build_genome<R>(&self, index: usize, rng: &mut R) -> G
where
R: Rng + Sized;
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct EmptyPopulationBuilder {
_empty: PhantomData<bool>,
}
impl EmptyPopulationBuilder {
pub fn with_genome_builder<B, G>(
self,
genome_builder: B,
) -> PopulationWithGenomeBuilderBuilder<B, G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
PopulationWithGenomeBuilderBuilder {
_g: PhantomData,
genome_builder,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct PopulationWithGenomeBuilderBuilder<B, G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
_g: PhantomData<G>,
genome_builder: B,
}
impl<B, G> PopulationWithGenomeBuilderBuilder<B, G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
pub fn of_size(
self,
population_size: usize,
) -> PopulationWithGenomeBuilderAndSizeBuilder<B, G> {
PopulationWithGenomeBuilderAndSizeBuilder {
_g: self._g,
genome_builder: self.genome_builder,
population_size,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct PopulationWithGenomeBuilderAndSizeBuilder<B, G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
_g: PhantomData<G>,
genome_builder: B,
population_size: usize,
}
impl<B, G> PopulationWithGenomeBuilderAndSizeBuilder<B, G>
where
B: GenomeBuilder<G>,
G: Genotype,
{
pub fn uniform_at_random(self) -> Population<G> {
PopulationBuilder::build_population(
&self.genome_builder,
self.population_size,
get_rng(random_seed()),
)
}
pub fn using_seed(self, seed: Seed) -> Population<G> {
PopulationBuilder::build_population(
&self.genome_builder,
self.population_size,
get_rng(seed),
)
}
}
pub fn build_population() -> EmptyPopulationBuilder {
EmptyPopulationBuilder {
_empty: PhantomData,
}
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, PartialEq)]
pub struct BinaryEncodedGenomeBuilder {
genome_length: usize,
}
impl BinaryEncodedGenomeBuilder {
pub fn new(genome_length: usize) -> Self {
BinaryEncodedGenomeBuilder { genome_length }
}
}
impl GenomeBuilder<Vec<bool>> for BinaryEncodedGenomeBuilder {
fn build_genome<R>(&self, _index: usize, rng: &mut R) -> Vec<bool>
where
R: Rng + Sized,
{
(0..self.genome_length).map(|_| rng.gen()).collect()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ValueEncodedGenomeBuilder<V> {
genome_length: usize,
min_value: V,
max_value: V,
}
impl<V> ValueEncodedGenomeBuilder<V> {
pub fn new(genome_length: usize, min_value: V, max_value: V) -> Self {
ValueEncodedGenomeBuilder {
genome_length,
min_value,
max_value,
}
}
}
impl<V> GenomeBuilder<Vec<V>> for ValueEncodedGenomeBuilder<V>
where
V: Clone + Debug + PartialEq + PartialOrd + SampleUniform + Send + Sync,
{
fn build_genome<R>(&self, _: usize, rng: &mut R) -> Vec<V>
where
R: Rng + Sized,
{
(0..self.genome_length)
.map(|_| rng.gen_range(self.min_value.clone()..self.max_value.clone()))
.collect()
}
}
#[cfg(feature = "fixedbitset")]
mod fixedbitset_genome_builder {
use super::{BinaryEncodedGenomeBuilder, GenomeBuilder};
use fixedbitset::FixedBitSet;
use rand::Rng;
impl GenomeBuilder<FixedBitSet> for BinaryEncodedGenomeBuilder {
fn build_genome<R>(&self, _index: usize, rng: &mut R) -> FixedBitSet
where
R: Rng + Sized,
{
let mut genome = FixedBitSet::with_capacity(self.genome_length);
for bit in 0..self.genome_length {
genome.set(bit, rng.gen());
}
genome
}
}
}
#[cfg(feature = "smallvec")]
mod smallvec_genome_builder {
use super::{BinaryEncodedGenomeBuilder, GenomeBuilder, ValueEncodedGenomeBuilder};
use rand::{distributions::uniform::SampleUniform, Rng};
use smallvec::{Array, SmallVec};
use std::fmt::Debug;
impl<A> GenomeBuilder<SmallVec<A>> for BinaryEncodedGenomeBuilder
where
A: Array<Item = bool> + Sync,
{
fn build_genome<R>(&self, _index: usize, rng: &mut R) -> SmallVec<A>
where
R: Rng + Sized,
{
(0..self.genome_length).map(|_| rng.gen()).collect()
}
}
impl<A, V> GenomeBuilder<SmallVec<A>> for ValueEncodedGenomeBuilder<V>
where
A: Array<Item = V> + Sync,
V: Clone + Debug + PartialEq + PartialOrd + SampleUniform + Send + Sync,
{
fn build_genome<R>(&self, _: usize, rng: &mut R) -> SmallVec<A>
where
R: Rng + Sized,
{
(0..self.genome_length)
.map(|_| rng.gen_range(self.min_value.clone()..self.max_value.clone()))
.collect()
}
}
}
#[cfg(test)]
mod tests;