pub trait GroupTrait<T, const N: usize, const R: usize> {
type Err: Debug;
type Out: Serialize;
// Required methods
fn new(data: [T; N]) -> Self;
fn one_cycle_with_output(&mut self) -> Result<Self::Out, Self::Err>;
fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Individual<T>>
where T: 'a;
// Provided methods
fn init<I>() -> Self
where I: InitializerTrait<T, N>,
Self: Sized { ... }
fn reset_id(&self) { ... }
fn clone_values(&self) -> Vec<T>
where T: Clone { ... }
}Expand description
A trait for evolutionary processes over a group of individuals.
This trait defines a method, one_cycle_with_output. When it is called, it should perform three steps.
-
Fitness: Assign a fitness score to each individual. These scores depend on all individuals in the group.
-
Select: Select individuals based on the fitness scores. Unselected individuals are removed from the group.
-
Replenish: Replenish the group with new individuals. Create them from remaining ones.
Optionally, you can output data about this cycle. If you don’t want to output any data, set type Out = ();.
T- A type of individuals of this group.N- The number of individuals.R- The number of individuals after individuals are reduced by selector.
§Example
use std::{collections::{HashMap, HashSet}, mem::swap, rc::Rc};
use scarlet_queen_core::{EachCrateIndividual, FitnessIndividualTrait, GroupTrait, Individual, InitializerTrait, ReplenisherIndividualTrait, SelectorIndividualTrait};
#[derive(PartialEq, Eq, Debug)]
struct IndividualWrapper<const N: usize, const R: usize>(Rc<Individual<u8>>);
impl<const N: usize, const R: usize> IndividualWrapper<N, R> {
fn new_for_test(id: usize, value: u8) -> IndividualWrapper<N, R> {
IndividualWrapper(Rc::new(Individual::new_with_id(id, value)))
}
}
impl<const N: usize, const R: usize> EachCrateIndividual for IndividualWrapper<N, R> {
type Item = u8;
fn new(individual: &Rc<Individual<Self::Item>>) -> Self {
IndividualWrapper(Rc::clone(individual))
}
fn get_individual(&self) -> &Individual<Self::Item> {
&self.0
}
}
impl<const N: usize, const R: usize> FitnessIndividualTrait for IndividualWrapper<N, R> {
fn fitness(&self, other: &Self) -> usize {
if self.get_value() >= other.get_value() {
1
} else {
0
}
}
}
impl<const N: usize, const R: usize> SelectorIndividualTrait<R> for IndividualWrapper<N, R> {
type Err = String;
fn selected_ids<'a, G>(
group: G,
_scores: std::collections::HashMap<usize, usize>,
) -> Result<std::collections::HashSet<usize>, Self::Err>
where
G: IntoIterator<Item = &'a Self>,
Self: 'a {
let group: Vec<&IndividualWrapper<N, R>> = group.into_iter().collect::<Vec<&IndividualWrapper<N, R>>>();
if group.len() < R {
return Err(String::from("The size of group is not enough."));
};
Ok(
group
.into_iter()
.map(|v| v.get_id())
.take(R)
.collect::<HashSet<usize>>()
)
}
}
impl<const N: usize, const R: usize> ReplenisherIndividualTrait<N, R> for IndividualWrapper<N, R> {
fn replenish<'a, G>(group: G) -> Vec<<Self as EachCrateIndividual>::Item>
where
G: IntoIterator<Item = &'a Self>,
Self: 'a {
group
.into_iter()
.map(|v| *v.get_value())
.collect::<Vec<u8>>()
.into_iter()
.cycle()
.take(N - R)
.collect::<Vec<u8>>()
}
}
#[derive(PartialEq, Eq, Debug)]
struct Group<const N: usize, const R: usize>(Vec<IndividualWrapper<N, R>>);
impl<const N: usize, const R: usize> GroupTrait<u8, N, R> for Group<N, R> {
type Err = String;
type Out = ();
fn new(data: [u8; N]) -> Self {
Group(
data
.into_iter()
.enumerate()
.map(|(i, v)| IndividualWrapper::new_for_test(i, v))
.collect::<Vec<_>>()
)
}
fn one_cycle_with_output(&mut self) -> Result<(), Self::Err> {
let scores: HashMap<usize, usize> = IndividualWrapper::fitness_group(self.0.iter());
self.0.sort_by_key(|v| -(*scores.get(&v.get_id()).unwrap() as isize));
let selector: HashSet<usize> = IndividualWrapper::selected_ids(self.0.iter(), scores)?;
let mut data_for_edit: Vec<IndividualWrapper<N, R>> = Vec::new();
swap(&mut data_for_edit, &mut self.0);
self.0 = data_for_edit
.into_iter()
.filter_map(|v| {
if selector.contains(&v.get_id()) {
Some(v)
} else {
None
}
})
.collect::<Vec<IndividualWrapper<N, R>>>();
let new_individuals: Vec<u8> = IndividualWrapper::replenish(self.0.iter());
self.0.extend(
new_individuals
.into_iter()
.map(|v| IndividualWrapper::new(&Rc::new(Individual::new_with_id(0, v)))),
);
self.reset_id();
Ok(())
}
fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Individual<u8>>
where
u8: 'a {
self.0.iter().map(|v| v.get_individual())
}
}
struct Initializer {}
impl<const N: usize> InitializerTrait<u8, N> for Initializer {
fn initialize() -> [u8; N] {
let mut i: u8 = 0;
[0; N].map(|_| {
i += 1;
i - 1
})
}
}
let mut group: Group<15, 12> = Group::init::<Initializer>();
group.one_cycle_with_output().unwrap();
assert_eq!(group.clone_values(), vec![14u8, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 14, 13, 12]);Required Associated Types§
Required Methods§
Sourcefn new(data: [T; N]) -> Self
fn new(data: [T; N]) -> Self
Create Self from an array.
The return value is already assigned a number.
data- An array of individuals
Sourcefn one_cycle_with_output(&mut self) -> Result<Self::Out, Self::Err>
fn one_cycle_with_output(&mut self) -> Result<Self::Out, Self::Err>
Run one cycle with outputing and update individuals.
The elements of self must be already assigned a number before calling this method.
Sourcefn iter<'a>(&'a self) -> impl Iterator<Item = &'a Individual<T>>where
T: 'a,
fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Individual<T>>where
T: 'a,
Create an iterator of individuals.
'a- A lifetime ofself.
Provided Methods§
Sourcefn init<I>() -> Selfwhere
I: InitializerTrait<T, N>,
Self: Sized,
fn init<I>() -> Selfwhere
I: InitializerTrait<T, N>,
Self: Sized,
Initialize Self by I algorithm.
The elements of self must be already assigned a number.
I- An algorithm of initializing.(The type which has the algorithm)
Sourcefn clone_values(&self) -> Vec<T>where
T: Clone,
fn clone_values(&self) -> Vec<T>where
T: Clone,
Clone individuals of this group.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.