diff --git a/gemla/src/bracket/genetic_node.rs b/gemla/src/bracket/genetic_node.rs index f72da1a..08af901 100644 --- a/gemla/src/bracket/genetic_node.rs +++ b/gemla/src/bracket/genetic_node.rs @@ -53,8 +53,7 @@ pub trait GeneticNode { /// Used externally to wrap a node implementing the [`GeneticNode`] trait. Processes state transitions for the given node as /// well as signal recovery. Transition states are given by [`GeneticState`] #[derive(Debug, Serialize, Deserialize)] -pub struct GeneticNodeWrapper -{ +pub struct GeneticNodeWrapper { pub data: Option, state: GeneticState, pub iteration: u64, diff --git a/gemla/src/bracket/mod.rs b/gemla/src/bracket/mod.rs index 3a8986f..5096375 100644 --- a/gemla/src/bracket/mod.rs +++ b/gemla/src/bracket/mod.rs @@ -9,70 +9,83 @@ use anyhow::anyhow; use file_linked::FileLinked; use genetic_node::{GeneticNode, GeneticNodeWrapper}; use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use std::fmt::Debug; use std::fs::File; use std::io::ErrorKind; -use std::mem::replace; +use std::mem::swap; use std::path::Path; -/// As the bracket tree increases in height, `IterationScaling` can be used to configure the number of iterations that -/// a node runs for. +/// Creates a tournament style bracket for simulating and evaluating nodes of type `T` implementing [`GeneticNode`]. +/// These nodes are built upwards as a balanced binary tree starting from the bottom. This results in `Bracket` building +/// a separate tree of the same height then merging trees together. Evaluating populations between nodes and taking the strongest +/// individuals. /// -/// # Examples -/// -/// TODO -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "enumType", content = "enumContent")] -pub enum IterationScaling { - /// Scales the number of simulations linearly with the height of the bracket tree given by `f(x) = mx` where - /// x is the height and m is the linear constant provided. - Linear(u64), - /// Each node in a bracket is simulated the same number of times. - Constant(u64), -} - -impl Default for IterationScaling { - fn default() -> Self { - IterationScaling::Constant(1) - } -} - -#[derive(Debug, Serialize, Deserialize)] -struct Bracket -{ - tree: Option>>>, - iteration_scaling: IterationScaling, -} - -impl Bracket +/// [`GeneticNode`]: genetic_node::GeneticNode +pub struct Gemla where - T: GeneticNode + Serialize + Debug, + T: Serialize, { + data: FileLinked>>>>, +} + +impl Gemla +where + T: GeneticNode + Serialize + DeserializeOwned + Debug, +{ + pub fn new(path: &Path, overwrite: bool) -> Result { + match File::open(path) { + Ok(file) => { + drop(file); + + Ok(Gemla { + data: if overwrite { + FileLinked::new(Some(btree!(None)), path)? + } else { + FileLinked::from_file(path)? + }, + }) + } + Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla { + data: FileLinked::new(Some(btree!(None)), path)?, + }), + Err(error) => Err(Error::IO(error)), + } + } + + pub fn simulate(&mut self, steps: u64) -> Result<(), Error> { + self.data.mutate(|d| Gemla::increase_height(d, steps))?; + + self.data + .mutate(|d| Gemla::process_tree(d.as_mut().unwrap()))??; + + Ok(()) + } + fn build_empty_tree(size: usize) -> Tree>> { if size <= 1 { btree!(None) } else { btree!( None, - Bracket::build_empty_tree(size - 1), - Bracket::build_empty_tree(size - 1) + Gemla::build_empty_tree(size - 1), + Gemla::build_empty_tree(size - 1) ) } } - fn increase_height(&mut self, amount: u64) { + fn increase_height(tree: &mut Option>>>, amount: u64) { for _ in 0..amount { - let height = self.tree.as_ref().unwrap().height(); - let tree = replace(&mut self.tree, None); - drop(replace( - &mut self.tree, - Some(btree!( + let height = tree.as_ref().unwrap().height(); + let temp = tree.take(); + swap( + tree, + &mut Some(btree!( None, - tree.unwrap(), - Bracket::build_empty_tree(height as usize) + temp.unwrap(), + Gemla::build_empty_tree(height as usize) )), - )); + ); } } @@ -80,8 +93,8 @@ where if tree.val.is_none() { match (&mut tree.left, &mut tree.right) { (Some(l), Some(r)) => { - Bracket::process_tree(&mut (*l))?; - Bracket::process_tree(&mut (*r))?; + Gemla::process_tree(&mut (*l))?; + Gemla::process_tree(&mut (*r))?; let left_node = (*l).val.as_ref().unwrap().data.as_ref().unwrap(); let right_node = (*r).val.as_ref().unwrap().data.as_ref().unwrap(); @@ -102,69 +115,6 @@ where Ok(()) } - - fn process(&mut self) -> Result<(), Error> { - Bracket::process_tree(self.tree.as_mut().unwrap())?; - - Ok(()) - } -} - -/// Creates a tournament style bracket for simulating and evaluating nodes of type `T` implementing [`GeneticNode`]. -/// These nodes are built upwards as a balanced binary tree starting from the bottom. This results in `Bracket` building -/// a separate tree of the same height then merging trees together. Evaluating populations between nodes and taking the strongest -/// individuals. -/// -/// [`GeneticNode`]: genetic_node::GeneticNode -pub struct Gemla -where T: Serialize -{ - data: FileLinked>, -} - -impl Gemla -where - T: GeneticNode + Serialize + DeserializeOwned + Debug, -{ - pub fn new(path: &Path, overwrite: bool) -> Result { - match File::open(path) { - Ok(file) => { - drop(file); - - Ok(Gemla { - data: if overwrite { - FileLinked::new( - Bracket { - tree: Some(btree!(None)), - iteration_scaling: IterationScaling::default(), - }, - path, - )? - } else { - FileLinked::from_file(path)? - }, - }) - } - Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla { - data: FileLinked::new( - Bracket { - tree: Some(btree!(None)), - iteration_scaling: IterationScaling::default(), - }, - path, - )?, - }), - Err(error) => Err(Error::IO(error)), - } - } - - pub fn simulate(&mut self, steps: u64) -> Result<(), Error> { - self.data.mutate(|b| b.increase_height(steps))?; - - self.data.mutate(|b| b.process())??; - - Ok(()) - } } #[cfg(test)]