use crate::error::GaError;
use crate::fitness::FitnessFnWrapper;
use crate::genotypes::Binary as BinaryGenotype;
use crate::operations::mutation::ValueMutable;
use crate::traits::ChromosomeT;
use std::borrow::Cow;
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Binary {
pub dna: Vec<BinaryGenotype>,
pub fitness: f64,
pub age: usize,
#[cfg_attr(feature = "serde", serde(skip, default))]
pub fitness_fn: FitnessFnWrapper<BinaryGenotype>,
}
impl ChromosomeT for Binary {
type Gene = BinaryGenotype;
fn dna(&self) -> &[Self::Gene] {
&self.dna
}
fn dna_mut(&mut self) -> &mut [Self::Gene] {
&mut self.dna
}
fn set_dna<'a>(&mut self, dna: Cow<'a, [Self::Gene]>) -> &mut Self {
self.dna = match dna {
Cow::Borrowed(slice) => slice.to_vec(),
Cow::Owned(vec) => vec,
};
self
}
fn set_fitness_fn<F>(&mut self, fitness_fn: F) -> &mut Self
where
F: Fn(&[BinaryGenotype]) -> f64 + Send + Sync + 'static,
{
self.fitness_fn = FitnessFnWrapper::new(fitness_fn);
self
}
fn calculate_fitness(&mut self) {
self.fitness = self.fitness_fn.call(&self.dna);
}
fn fitness(&self) -> f64 {
self.fitness
}
fn set_fitness(&mut self, fitness: f64) -> &mut Self {
self.fitness = fitness;
self
}
fn set_age(&mut self, age: usize) -> &mut Self {
self.age = age;
self
}
fn age(&self) -> usize {
self.age
}
}
impl Default for Binary {
fn default() -> Self {
Self {
dna: Vec::new(),
fitness: f64::NAN,
age: 0,
fitness_fn: FitnessFnWrapper::default(),
}
}
}
impl Binary {
pub fn new() -> Self {
Self {
dna: Vec::new(),
fitness: f64::NAN,
age: 0,
fitness_fn: FitnessFnWrapper::default(),
}
}
pub fn phenotype(&self) -> String {
self.dna
.iter()
.map(|gene| if gene.value { '1' } else { '0' })
.collect()
}
pub fn dna_from_string(&mut self, s: &str) -> Result<(), GaError> {
let mut dna = Vec::with_capacity(s.len());
for (index, char) in s.chars().enumerate() {
match char {
'1' => dna.push(BinaryGenotype {
id: index as i32,
value: true,
}),
'0' => dna.push(BinaryGenotype {
id: index as i32,
value: false,
}),
_ => {
return Err(GaError::ValidationError(format!(
"Invalid character '{}' at position {}; only '1' and '0' are allowed",
char, index
)));
}
}
}
self.dna = dna;
Ok(())
}
}
impl ValueMutable for Binary {
fn bit_flip_mutate(&mut self) {
crate::operations::mutation::bit_flip::bit_flip(self);
}
}
impl fmt::Display for Binary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}] fitness={:.6}", self.phenotype(), self.fitness)
}
}