use crate::node::Node;
use crate::ops::operation::Op;
use crate::{Factory, GraphChromosome, NodeType, TreeChromosome, TreeIterator};
use radiate_core::genome::Gene;
use radiate_core::{AlterResult, Mutate};
use radiate_core::{Chromosome, random_provider};
use std::sync::{Arc, Mutex};
pub struct OperationMutator {
rate: f32,
replace_rate: f32,
}
impl OperationMutator {
pub fn new(rate: f32, replace_rate: f32) -> Self {
if !(0.0..=1.0).contains(&rate) {
panic!("rate must be between 0.0 and 1.0");
}
if !(0.0..=1.0).contains(&replace_rate) {
panic!("replace_rate must be between 0.0 and 1.0");
}
OperationMutator { rate, replace_rate }
}
}
impl<T> Mutate<GraphChromosome<Op<T>>> for OperationMutator
where
T: Clone + PartialEq + Default,
{
fn rate(&self) -> f32 {
self.rate
}
#[inline]
fn mutate_chromosome(&self, chromosome: &mut GraphChromosome<Op<T>>, rate: f32) -> AlterResult {
let mutation_indexes = (0..chromosome.len())
.filter(|_| random_provider::random::<f32>() < rate)
.collect::<Vec<usize>>();
if mutation_indexes.is_empty() {
return 0.into();
}
for i in mutation_indexes.iter() {
let current_node = chromosome.get(*i);
if current_node.node_type() == NodeType::Input
|| current_node.node_type() == NodeType::Output
{
continue;
}
match current_node.allele() {
Op::MutableConst {
name,
arity,
value,
supplier: get_value,
modifier,
operation,
} => {
let new_value = get_value();
let new_value = if random_provider::random::<f32>() < self.replace_rate {
new_value
} else {
modifier(value)
};
(*chromosome.as_mut()[*i].value_mut()) = Op::MutableConst {
name,
arity: *arity,
value: new_value,
modifier: Arc::clone(modifier),
supplier: Arc::clone(get_value),
operation: Arc::clone(operation),
};
}
_ => {
let new_op: Option<Op<T>> = chromosome
.store()
.map(|store| store.new_instance(current_node.node_type()));
if let Some(new_op) = new_op {
if new_op.arity() == current_node.arity() {
(*chromosome.as_mut()[*i].value_mut()) = new_op;
}
}
}
}
}
mutation_indexes.len().into()
}
}
impl<T> Mutate<TreeChromosome<Op<T>>> for OperationMutator
where
T: Clone + PartialEq + Default,
{
fn rate(&self) -> f32 {
self.rate
}
#[inline]
fn mutate_chromosome(&self, chromosome: &mut TreeChromosome<Op<T>>, rate: f32) -> AlterResult {
let store = chromosome.get_store();
if let Some(store) = store {
let count = Arc::new(Mutex::new(0));
let cloned_count = Arc::clone(&count);
let root = chromosome.root_mut();
root.apply(move |node| {
if random_provider::random::<f32>() < rate {
match node.allele() {
Op::MutableConst {
name,
arity,
value,
supplier: get_value,
modifier,
operation,
} => {
let new_value = get_value();
let new_value = if random_provider::random::<f32>() < self.replace_rate
{
new_value
} else {
modifier(value)
};
(*node.value_mut()) = Op::MutableConst {
name,
arity: *arity,
value: new_value,
modifier: Arc::clone(modifier),
supplier: Arc::clone(get_value),
operation: Arc::clone(operation),
};
(*cloned_count.lock().unwrap()) += 1;
}
_ => {
let new_op: Op<T> = store.new_instance(node.node_type());
if new_op.arity() == node.arity() {
*node.value_mut() = new_op;
(*cloned_count.lock().unwrap()) += 1;
}
}
}
}
});
return (*count.lock().unwrap()).into();
} else {
0.into()
}
}
}