use super::node::{GpNode, Node};
use crate::traits::{ChromosomeT, GeneT, LinearChromosome, VectorFitness};
use std::borrow::Cow;
use std::fmt;
use std::sync::Arc;
type TreeFitnessFn<N> = Option<Arc<dyn Fn(&Node<N>) -> f64 + Send + Sync>>;
#[derive(Clone, Default, Debug)]
pub struct GpGene;
impl GeneT for GpGene {
fn set_id(&mut self, _id: i32) -> &mut Self {
self
}
}
pub trait TreeChromosome: ChromosomeT {
type GpNodeType: GpNode;
fn tree(&self) -> &Node<Self::GpNodeType>;
fn tree_mut(&mut self) -> &mut Node<Self::GpNodeType>;
fn depth(&self) -> usize;
fn node_count(&self) -> usize;
}
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(bound(
serialize = "N: serde::Serialize",
deserialize = "N: for<'de2> serde::Deserialize<'de2>"
))
)]
pub struct GpChromosome<N: GpNode> {
pub root: Box<Node<N>>,
fitness: f64,
age: usize,
#[cfg_attr(feature = "serde", serde(default))]
fitness_values: Vec<f64>,
#[cfg_attr(feature = "serde", serde(skip, default = "default_fitness_fn"))]
fitness_fn: TreeFitnessFn<N>,
}
#[cfg(feature = "serde")]
fn default_fitness_fn<N: GpNode>() -> TreeFitnessFn<N> {
None
}
impl<N: GpNode + std::fmt::Debug> std::fmt::Debug for GpChromosome<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GpChromosome")
.field("root", &self.root)
.field("fitness", &self.fitness)
.field("age", &self.age)
.finish_non_exhaustive()
}
}
impl<N: GpNode> Clone for GpChromosome<N> {
fn clone(&self) -> Self {
GpChromosome {
root: self.root.clone(),
fitness: self.fitness,
age: self.age,
fitness_values: self.fitness_values.clone(),
fitness_fn: self.fitness_fn.clone(),
}
}
}
impl<N: GpNode + Default> Default for GpChromosome<N> {
fn default() -> Self {
GpChromosome {
root: Box::new(Node::Terminal(N::default())),
fitness: 0.0,
age: 0,
fitness_values: Vec::new(),
fitness_fn: None,
}
}
}
impl<N: GpNode> GpChromosome<N> {
pub fn with_root(root: Box<Node<N>>) -> Self {
GpChromosome {
root,
fitness: 0.0,
age: 0,
fitness_values: Vec::new(),
fitness_fn: None,
}
}
pub fn set_tree_fitness_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&Node<N>) -> f64 + Send + Sync + 'static,
{
self.fitness_fn = Some(Arc::new(f) as Arc<dyn Fn(&Node<N>) -> f64 + Send + Sync>);
self
}
}
impl<N: GpNode + Default> ChromosomeT for GpChromosome<N> {
type Gene = GpGene;
fn calculate_fitness(&mut self) {
if let Some(ref f) = self.fitness_fn {
self.fitness = f(&self.root);
}
}
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<N: GpNode + Default> TreeChromosome for GpChromosome<N> {
type GpNodeType = N;
fn tree(&self) -> &Node<N> {
&self.root
}
fn tree_mut(&mut self) -> &mut Node<N> {
&mut self.root
}
fn depth(&self) -> usize {
self.root.depth()
}
fn node_count(&self) -> usize {
self.root.node_count()
}
}
impl<N: GpNode + Default> VectorFitness for GpChromosome<N> {
fn fitness_values(&self) -> &[f64] {
&self.fitness_values
}
fn set_fitness_values(&mut self, values: Vec<f64>) {
self.fitness_values = values;
}
}
fn write_node<N: GpNode + fmt::Display>(node: &Node<N>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match node {
Node::Terminal(v) => write!(f, "{}", v),
Node::Function { value, children } => {
write!(f, "({}", value)?;
for child in children {
write!(f, " ")?;
write_node(child, f)?;
}
write!(f, ")")
}
}
}
impl<N: GpNode + fmt::Display + Default> fmt::Display for GpChromosome<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write_node(&self.root, f)
}
}
impl<N: GpNode + Default> LinearChromosome for GpChromosome<N> {
fn dna(&self) -> &[Self::Gene] {
panic!(
"GpChromosome::dna() is not supported — use GpChromosome with GpGa, not Ga. \
TreeChromosome has no flat DNA slice."
)
}
fn dna_mut(&mut self) -> &mut [Self::Gene] {
panic!(
"GpChromosome::dna_mut() is not supported — use GpChromosome with GpGa, not Ga. \
TreeChromosome has no flat DNA slice."
)
}
fn set_dna<'a>(&mut self, _dna: Cow<'a, [Self::Gene]>) -> &mut Self {
panic!(
"GpChromosome::set_dna() is not supported — use GpChromosome with GpGa, not Ga. \
TreeChromosome has no flat DNA slice."
)
}
fn set_fitness_fn<F>(&mut self, _fitness_fn: F) -> &mut Self
where
F: Fn(&[Self::Gene]) -> f64 + Send + Sync + 'static,
{
self
}
}